#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) Dan Scott <dan@coffeecode.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Google Books v1 API 

Find a Google Book ID for a given ISBN, then add it to a bookshelf

Authentication based on Joe Gregorio's buzz.py sample
"""

__author__ = 'Dan Scott <dan@coffeecode.net>'

import httplib2
import sys

from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run
from apisecrets import DEV_API_KEY, OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET

class GBooks():
    """Defines methods for accessing Google Books API v1"""

    def __init__(self):
        """Initialize the GBooks object"""

        # Set up a Flow object to be used if we need to authenticate. This
        # sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with
        # the information it needs to authenticate. Note that it is called
        # the Web Server Flow, but it can also handle the flow for native
        # applications <http://code.google.com/apis/accounts/docs/OAuth2.html#IA>
        # The client_id client_secret are copied from the API Access tab on
        # the Google APIs Console <http://code.google.com/apis/console>. When
        # creating credentials for this application be sure to choose an Application
        # type of "Installed application".
        _auth_flow = OAuth2WebServerFlow(
            client_id=OAUTH2_CLIENT_ID,
            client_secret=OAUTH2_CLIENT_SECRET,
            scope='https://www.googleapis.com/auth/books',
            user_agent='bookshelf-builder/1.0')

        # If the Credentials don't exist or are invalid run through the native client
        # flow. The Storage object will ensure that if successful the good
        # Credentials will get written back to a file.
        storage = Storage('books.dat')
        credentials = storage.get()
        if credentials is None or credentials.invalid:
            credentials = run(_auth_flow, storage)

        # Create an httplib2.Http object to handle our HTTP requests and authorize it
        # with our good Credentials.
        self.auth_http = httplib2.Http()
        self.auth_http = credentials.authorize(self.auth_http)

        self.service = build(
            serviceName="books", version="v1", developerKey=DEV_API_KEY
        )

    def vol_by_id(self, vol_id):
        """
        Return the volume metadata for a given volume ID
        """

        result = self.service.volumes().get(volumeId=vol_id).execute()

        return result

    def vol_by_query(self, query):
        """
        Return the metadata for all results for a given query
        """

        results = self.service.volumes().list(q=query).execute()

        return results

    def ids_by_isbn(self, isbn):
        """
        Given an ISBN, returns the matching Google Books IDs
        """

        results = self.vol_by_query("isbn:" + isbn)

        try:
            vol_ids = []
            for match in results['items']:
                vol_ids.append(match['id']) 
            return vol_ids
        except:
            print("ISBN %s: no match found in Google Books") % (isbn)

        return None
 
    def list_bookshelves(self, user_id):
        """List bookshelves for a given user"""

        try:
            shelves = self.service.bookshelves().list(
                userId=user_id
            ).execute(self.auth_http)
        except:
            print("Failed to list bookshelves for user %d" % (user_id))
            return None

        return shelves

    def add_volume(self, shelf_id, vol_id):
        """Add a volume to a user's book shelf

        This requires one authenticated API call per volume.
        """

        # Add the volume to the bookshelf
        # Requires an empty body argument? Okay.
        try:
            res = self.service.mylibrary().bookshelves().addVolume(
                body='', volumeId=vol_id, shelf=shelf_id
            ).execute(self.auth_http)
        except Exception as exc:
            print("Adding volume failed: %s" % (exc.resp))
            return None

        return res

    def search_bookshelf(self, shelf_id, query):
        """
        Search a given bookshelf using a query

        Should return a subset of the bookshelf, per the now-deprecated
        Data API. Unfortunately, this functionality does not appear to
        be available in the v1 Books API.

        See http://code.google.com/p/google-ajax-apis/issues/detail?id=587
        """

        try:
            res = self.service.mylibrary().bookshelves().list(
                shelf=shelf_id, q=query
            ).execute(self.auth_http)
        except Exception as exc:
            print("Searching bookshelf %s failed: %s" % (shelf_id, str(exc)))
            return None

        return res

def main(argv):
    """Exercise the basic methods of Google Books API v1"""
    shelf_id = '1001'
    marc_file = 'oss.marc'

    gbook = GBooks()

    print gbook.vol_by_query("apache derby")
    # print gbook.search_bookshelf(shelf_id, "apache derby")
    # print gbook.vol_by_id('nrUZAAAACAAJ')
    # print gbook.ids_by_isbn(isbn='0131855255')
    exit()

    import pymarc
    reader = pymarc.MARCReader(
        open(marc_file, mode='rb'), to_unicode=True
    )

    cnt = 0
    for record in reader:
        cnt = cnt + 1

        try:
            isbn = record['020']['a']
        except:
            print("* No ISBN for record # %s in file %s" % (cnt, marc_file))
            continue

        try:
            vol_ids = gbook.ids_by_isbn(isbn=isbn)
            if vol_ids is not None:
                gbook.add_volume(shelf_id, vol_ids[0])

        except Exception as exc:
            print("* Error processing record %s - %s" % (cnt, exc))

if __name__ == '__main__':
    main(sys.argv)
