import logging
import datetime
import time
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext import db
from cgi import parse_qs
from cStringIO import StringIO

from orangescape.model.server.util.ServerUtil import _get_class
from orangescape.model.server.util import pyjsonutil
from orangescape.model.server.util.listutil import split_seq
from orangescape.model.server.Constants import GFS_MAX_COMMIT_SIZE
from orangescape.model.server.Data import PrimaryData, SecondaryData
from orangescape.model.server.util.gfsutil import delete, put, get
from google.appengine.api import datastore

from orangescape.model.engine.util.NumericUtil import is_a_number

class BaseSerializer():

    def __init__(self, captureIds=False):
        self.stringBuffer = StringIO()
        self.writeStr('{')
        self.captureIds = captureIds
        if self.captureIds:
            self.idList = list()

    def writeStr(self, s):
        self.stringBuffer.write(s)

    def getStr(self):
        return self.stringBuffer.getvalue()

    def getIdList(self):
        return self.idList if self.captureIds else []

    def serialize(self, entityClass, params):
        try:
            (moreRecords, lastRecordKey) = self.get_serialized_data(entityClass, params)
            while moreRecords:
                params['__key__ >'] = lastRecordKey
                (moreRecords, lastRecordKey) = self.get_serialized_data(entityClass, params)

            self.writeStr('}')
            return self.getStr()

        except db.Timeout, e:
            logging.error('Timeout Error %s'%(e))
            return str({'error':params})

    def entityListToJsonStr(self, rs):
        strBuffer = StringIO()
        if not rs:
            return ''
#        logging.debug('Serializing %d records'%(len(rs)))
        for dataObject in rs:
            if self.captureIds:
                self.idList.append(dataObject.SheetId)

            strBuffer.write(pyjsonutil.write(dataObject.SheetId))
            strBuffer.write(':{')
            if not dataObject.Deleted:
                recordItems = list()
                for name, value in dataObject._dynamic_properties.iteritems():
                    recordItems.append(pyjsonutil.write(name))
                    recordItems.append(':')
                    recordItems.append(pyjsonutil.write(value))
                    recordItems.append(',')
                recordItems.append(pyjsonutil.write('SheetMetadataId'))
                recordItems.append(':')
                recordItems.append(pyjsonutil.write(dataObject.SheetMetadataId))
                recordItems.append(',')
                recordItems.append(pyjsonutil.write('SheetId'))
                recordItems.append(':')
                recordItems.append(pyjsonutil.write(dataObject.SheetId))
                recordItems.append(',')
                recordItems.append(pyjsonutil.write('ApplicationId'))
                recordItems.append(':')
                recordItems.append(pyjsonutil.write(dataObject.ApplicationId))
                recordItems.append(',')
                recordItems.append(pyjsonutil.write('ModifiedAt'))
                recordItems.append(':')
                recordItems.append(pyjsonutil.write(dataObject.ModifiedAt))
                strBuffer.write(''.join(recordItems))
            strBuffer.write('}')
            strBuffer.write(',')
        return strBuffer.getvalue()[:-1]

    def get_serialized_data(self, entityClass, params, orderBy = None):
        query = entityClass.all()
        if orderBy:
            query.order(orderBy)

        for filterColumn, filterValue in params.iteritems():
            query.filter(filterColumn, filterValue)

        limit = 400
        offset = 0
        totalLimit = 800
        lastRecordKey = None
        n = 0
        entities = query.fetch(limit, offset)
        while entities and offset <= (totalLimit-limit):
            lastRecordKey = entities[-1].key()
            n += len(entities)

            self.writeStr(self.entityListToJsonStr(entities))
            self.writeStr(',')
            offset+=limit
            if len(entities)==limit:
                entities = query.fetch(limit, offset)
            else:
                entities = None
        entities = None
        return (n>=totalLimit, lastRecordKey)
