from skyliveDaemon.Database.dbschema import SkyliveUsers, SubscriptionsType, UserHours 
from skyliveDaemon.Database.dbschema import UserSubscriptions, TelescopeBooking, SkyliveStore
from skyliveDaemon.Database.dbschema import MontlyHours, HoursTypes
from axiom.attributes import AND, OR
from twisted.internet import defer
import time
from epsilon import extime
import logging
from dateutil.relativedelta import relativedelta
import datetime
import md5

log = logging.getLogger("DBLog")

store = SkyliveStore

def getCities():
   ua = store.query(SkyliveUsers, SkyliveUsers.citta != None).getColumn('citta')
   return list(ua.distinct())

def getUser(username=False):
   if username:
      return store.query(SkyliveUsers, SkyliveUsers.username == unicode(username))
   return False

def getOneUser(username=False):
   if username:
      return store.findFirst(SkyliveUsers, SkyliveUsers.username == unicode(username))
   return False

def newUser(data=False, pwd=False):
   iscr = extime.Time.fromPOSIXTimestamp(time.time())
   if data and pwd:
      try:
         mlist=False
         if data['mlist'] == 'yes':
            mlist=True
         strm = unicode(unicode(data['name'])+unicode(data['surname'])+unicode(data['email']))
         m = md5.new(strm)
         uid = m.hexdigest()
         SkyliveUsers(store=store, nome=data['name'], cognome=data['surname'], 
                preferenza=data['prefobj'], email=data['email'], citta=data['city'],
                username=data['username'], password=unicode(pwd), nazione=data['nation'],
                lingua=data['language'], active=True, uniqueid=unicode(uid), tsiscrizione=iscr,
                timezone=unicode(data['tzone']), mlist=True)
         return True
      except:
         pass
   return False


def getUserFromUUID(uuid=False):
   if uuid:
      return store.findFirst(SkyliveUsers, SkyliveUsers.uniqueid == unicode(uuid))
   return False


def getSubscriptions(username):
   return store.query(UserSubscriptions, UserSubscriptions.username==unicode(username))

def getHours(username):
   return store.query(UserHours, UserHours.username==unicode(username))

def getMountlyHours(username):
   return store.query(MontlyHours, MontlyHours.username==unicode(username))


def getSubsTypes():
   return list(store.query(SubscriptionsType))

def getHourTypes():
   return list(store.query(HoursTypes))

def getUserlistResult(data):
   # Qui sarebbe meglio ritornare una deferred!
   qstr=[]
   for k in data.keys():
      if hasattr(SkyliveUsers, k):
         if data[k]:
            print data[k]
            if '%' in data[k]:
               if data[k][0] == '%' and data[k][-1] == '%':
                  qstr.append(getattr(SkyliveUsers, k).like(unicode(data[k])))
               elif data[k][0] == '%':
                  qstr.append(getattr(SkyliveUsers, k).endswith(unicode(data[k][1:])))
               elif data[k][-1] == '%':
                  qstr.append(getattr(SkyliveUsers, k).startswith(unicode(data[k][:-1])))
            else:
               qstr.append(getattr(SkyliveUsers, k) == data[k])
   log.debug("QSTR, %s" % qstr)
   res = list(store.query(SkyliveUsers, AND(*qstr)))
   if len(res) > 0:
      return res
   return str(data)


def emailExist(email):
   if store.count(SkyliveUsers, SkyliveUsers.email == unicode(email)) > 0:
      log.debug("EMAIL %s EXISTS" % str(email))
      return True
   log.debug("EMAIL %s DON'T EXISTS" % str(email))
   return False


def getRegUserNum():
   return store.count(SkyliveUsers)

def userExists(username):
   if store.count(SkyliveUsers, SkyliveUsers.username == unicode(username)) > 0:
      return True
   return False


def addNewMonths(user, ht, hm):
   htdata = store.findFirst(HoursTypes, HoursTypes.name==unicode(ht))
   if htdata:
      uht = store.findFirst(MontlyHours, AND(MontlyHours.hourstype==unicode(ht),
                                           MontlyHours.username==unicode(user)))
      if uht:
         uht.howmany=+int(hm)
      else:
         MontlyHours(store=store, username=unicode(user), hourstype=unicode(ht), howmany=int(hm), donemonth=0)

def addNewHours(user, ht, hm):
   htdata = store.findFirst(HoursTypes, HoursTypes.name==unicode(ht))
   if htdata:
      uht = store.findFirst(UserHours, AND(UserHours.hourstype==unicode(ht),
                                           UserHours.username==unicode(user)))
      if uht:
         uht.hours=+int(hm)
      else:
         UserHours(store=store, username=unicode(user), hourstype=unicode(ht), hours=int(hm))
         
def addSubscription(user, sub):
   subdata = store.findFirst(SubscriptionsType, SubscriptionsType.name==unicode(sub))
   if subdata:
      usub = store.findFirst(UserSubscriptions, AND(UserSubscriptions.username==unicode(user), 
            UserSubscriptions.subname==unicode(sub)))
      if usub:
         usub.expiration = extime.Time.fromDatetime(
               usub.expiration.asDatetime()+relativedelta(months=+int(subdata.duration)))
         usub.expireadvised = False
      else:
         exp = extime.Time.fromDatetime(datetime.datetime.fromtimestamp(
               time.time())+relativedelta(months=+int(subdata.duration)))
         UserSubscriptions(store=store, username=unicode(user), price=subdata.price, expiration=exp, subname=subdata.name)


def deleteUser(username):
   store.query(SkyliveUsers, SkyliveUsers.username==unicode(username)).deleteFromStore()
   store.query(UserHours, UserHours.username == unicode(username)).deleteFromStore()
   store.query(MontlyHours, MontlyHours.username == unicode(username)).deleteFromStore()
   store.query(TelescopeBooking, TelescopeBooking.username == unicode(username)).deleteFromStore()
   store.query(UserSubscriptions, UserSubscriptions.username == unicode(username)).deleteFromStore()
   return True


def safeDelUser(uniqueid):
   user = getUserFromUUID(uniqueid)
   if user:
      howmany = store.count(SkyliveUsers, SkyliveUsers.username == unicode(user.username))
      store.query(SkyliveUsers, SkyliveUsers.uniqueid == unicode(uniqueid)).deleteFromStore()
      if howmany == 1:
         store.query(UserHours, UserHours.username == unicode(user.username)).deleteFromStore()
         store.query(MontlyHours, MontlyHours.username == unicode(user.username)).deleteFromStore()
         store.query(TelescopeBooking, TelescopeBooking.username == unicode(user.username)).deleteFromStore()
         store.query(UserSubscriptions, UserSubscriptions.username == unicode(user.username)).deleteFromStore()
   

def delSubscription(user, subname):
   return store.query(UserSubscriptions, AND(UserSubscriptions.subname==unicode(subname), 
      UserSubscriptions.username==unicode(user))).deleteFromStore()

def delUserHours(user, ht):
   return store.query(UserHours, AND(UserHours.hourstype==unicode(ht),
      UserHours.username==unicode(user))).deleteFromStore()

def delMontlyHours(user, ht):
   return store.query(MontlyHours, AND(MontlyHours.hourstype==unicode(ht),
      MontlyHours.username==unicode(user))).deleteFromStore()


def updateUserDetails(user, password, nome, cognome, citta, email, mlist='yes'):
   ret = store.findFirst(SkyliveUsers, SkyliveUsers.username==unicode(user))
   ret.updateUserDetails(password, nome, cognome, citta, email, mlist)

def checkUserPwd(usr, pwd, enc=False):
   if not enc:
      res = store.query(SkyliveUsers, AND(SkyliveUsers.username == unicode(usr),
               SkyliveUsers.password == unicode(pwd)))
   else:
      res = []
      resu = list(store.query(SkyliveUsers, SkyliveUsers.username == unicode(usr)))
      # We need to manage old database multiple users with the same username
      if len(resu) > 0:
         for u in resu:
            m = md5.new(str(u.password))
            if m.hexdigest() == pwd:
               res.append(u)

   log.debug("QUERY USERS RESULT: %s " % str(res))
   resus = []
   if len(list(res)) > 0:
      resus = list(res)
      try:
         resus[0].updateLastLogin()
         log.debug("LASTLOGIN UPDATED FOR %s " % str(usr))
      except:
         pass
   subs=set(list(store.query(UserSubscriptions, AND(
      OR(UserSubscriptions.expiration > extime.Time.fromPOSIXTimestamp(time.time()),
         UserSubscriptions.expiration == None),
      UserSubscriptions.username == unicode(usr))).getColumn('subname')))
   log.debug("QUERY SUBS RESULT: %s " % str(subs))
   resperm = []
   for name in subs:
      st = store.findFirst(SubscriptionsType, SubscriptionsType.name==name)
      if st:
         resperm += st.telescopes
   log.debug("QUERY RESPERM RESULT: %s " % str(set(resperm)))
   return [resus, resperm]


def cleanUserHours():
   log.debug("Deleting expired user hours")
   store.query(UserHours, UserHours.hours <= 0).deleteFromStore()

def cleanExpiredSubscriptions():
   log.debug("Deleting expired subscriptions")
   store.query(UserSubscriptions, 
      AND(UserSubscriptions.expiration <= extime.Time.fromPOSIXTimestamp(time.time()),
          UserSubscriptions.expiration != None, UserSubscriptions.expiredadvised == True)).deleteFromStore()


def cleanExpiredSubscriptionsOne():
   userzero = store.findFirst(UserSubscriptions,
      AND(UserSubscriptions.expiration <= extime.Time.fromPOSIXTimestamp(time.time()),
          UserSubscriptions.expiration != None, UserSubscriptions.expireadvised == True))
   if userzero:
      log.debug("Removing expired Subscrition %s for user %s" % (userzero.subname, userzero.username))
      store.query(UserSubscriptions,
         AND(UserSubscriptions.expiration <= extime.Time.fromPOSIXTimestamp(time.time()),
            UserSubscriptions.expiration != None, UserSubscriptions.expireadvised == True,
            UserSubscriptions.username==userzero.username, UserSubscriptions.subname==userzero.subname,
            UserSubscriptions.storeID==userzero.storeID)).deleteFromStore()
            #limit=1).deleteFromStore()
   return userzero

def cleanUserHoursOne():
   userzero = store.findFirst(UserHours, UserHours.hours <= 0)
   if userzero:
      log.debug("Removing zero hours for user %s" % str(userzero.username))
      store.query(UserHours, AND(UserHours.hours <= 0, UserHours.username==userzero.username, 
         UserHours.storeID==userzero.storeID)).deleteFromStore()
   return userzero

def checkCloseExpirationSubs():
   oneweek=3600*24*7
   userzero = store.findFirst(UserSubscriptions,
      AND(UserSubscriptions.expiration <= extime.Time.fromPOSIXTimestamp(time.time()+oneweek),
          UserSubscriptions.expiration != None, UserSubscriptions.expireadvised != True))
   if userzero:
      userzero.expireadvised = True
      user = store.findFirst(SkyliveUsers, SkyliveUsers.username==userzero.username)     
      return user, userzero
   return False, False

def assignMountlyHours():
   # to be shure we don't get in the empass of 
   # make something across a month change, we execute those actions
   # only from 1:00:00am to 22:59:59pm
   hnow = int(time.strftime("%H"))
   if hnow > 0 and hnow < 23:
      mnow = time.strftime("%m")
      ynow = int(time.strftime("%Y"))
      if mnow == "12":
         y = str(ynow+1)
         m="01"
      else:
         y= str(ynow)
         if int(mnow) < 9:
            m="0"+str(int(mnow)+1)
         else:
            m=str(int(mnow)+1)
      checkmount = int(y+m)
      mhours = store.findFirst(MontlyHours, MontlyHours.donemonth < checkmount)
      if mhours:
         mhours.donemonth = checkmount
         store.query(UserHours, AND(UserHours.username==mhours.username,
                                 UserHours.hourstype==mhours.hourstype)
                                 ).deleteFromStore()
         UserHours(store=store, hours=mhours.howmany, username=mhours.username, hourstype=mhours.hourstype)
         return mhours

   return False


def getBookingTime(start, stop, tel=None, username=None):
   start=extime.Time.fromPOSIXTimestamp(int(start))
   stop=extime.Time.fromPOSIXTimestamp(int(stop))
   if not tel and not username:
      where = AND(TelescopeBooking.timestart >= start, TelescopeBooking.timestop <= stop)
   elif tel and not username:
      where = AND(TelescopeBooking.timestart >= start, TelescopeBooking.timestop <= stop,
            TelescopeBooking.telescope == unicode(tel))
   elif username and not tel:
      where = AND(TelescopeBooking.timestart >= start, TelescopeBooking.timestop <= stop,
            TelescopeBooking.username == unicode(username))
   else:
      where = AND(TelescopeBooking.timestart >= start, TelescopeBooking.timestop <= stop,
            TelescopeBooking.username == unicode(username),
            TelescopeBooking.telescope == unicode(tel))
   return list(store.query(TelescopeBooking, where))

def getBookingNow(tel, ts=None):
   now = extime.Time.fromPOSIXTimestamp(time.time())
   if ts:
      now = extime.Time.fromPOSIXTimestamp(int(ts))
   return store.findFirst(TelescopeBooking, AND(TelescopeBooking.timestart <= now, TelescopeBooking.timestop >= now, 
         TelescopeBooking.telescope == unicode(tel), OR(TelescopeBooking.result==unicode("GOING"),
            TelescopeBooking.result==unicode("NOTYET"))))

def cleanExpiredBooking(tel):
   now =  extime.Time.fromPOSIXTimestamp(time.time())
   res = store.query(TelescopeBooking, 
         AND(TelescopeBooking.timestop < now, OR(TelescopeBooking.result==unicode("GOING"),
            TelescopeBooking.result==unicode("NOTYET"))),
         limit=3)
   num = len(res)
   if num > 0:
      for r in res:
         res2 = store.findFirst(HoursTypes, HoursTypes.name==r.hourstype)
         r.setOk()
         if res2 and len(res2) > 0:
            perc = res2.rechargeperc
            if int(perc) > 0 and int(perc) < 100:
               if r.result==u'NOTYET':
                  pass
                  # In questo caso le restituiamo tutte in ogni caso. Il
                  # server  era down?
                  #
               else:
                  start = r.timestart.asPOSIXTimestamp()
                  stop = r.timestop.asPOSIXTimestamp()
                  hm = int(((stop-start)+1)/3600)
                  totsign = 60*hm
                  u = r.username
                  t = r.type
                  # becca le somme nella TelescopeStatusData, ma i calcoli falli
                  # in un thread! Magari metti come return anche in caso di OK
                  # una callback???

            return False
         return True

   # UPDATE A OK/NO?:
   return False



def nowSendEmail(offset, limit, dest, language, ulist, city='all'):

   if dest  == 'all':

      if city == 'all':
         if language == 'all':
            ret = list(store.query(SkyliveUsers, limit=limit, offset=offset))
         else:
            ret = list(store.query(SkyliveUsers, SkyliveUsers.lingua==unicode(language), limit=limit, offset=offset))
      else:
         if language == 'all':
            ret = list(store.query(SkyliveUsers, SkyliveUsers.citta==unicode(city), limit=limit, offset=offset))
         else:
            ret = list(store.query(SkyliveUsers, AND(SkyliveUsers.lingua==unicode(language),
                                                SkyliveUsers.citta==unicode(city)), limit=limit, offset=offset))

   elif dest == 'abb':
      if city == 'all':
         if language == 'all':
            ret = list(store.query(SkyliveUsers, UserSubscriptions.username==SkyliveUsers.username, limit=limit, offset=offset))
         else:
            ret = list(store.query(SkyliveUsers, AND(UserSubscriptions.username==SkyliveUsers.username,
                                                  SkyliveUsers.lingua==unicode(language)), limit=limit, offset=offset))
      else:
         if language == 'all':
            ret = list(store.query(SkyliveUsers, AND(UserSubscriptions.username==SkyliveUsers.username,
                                                SkyliveUsers.citta==unicode(city)), limit=limit, offset=offset))
         else:
            ret = list(store.query(SkyliveUsers, AND(UserSubscriptions.username==SkyliveUsers.username,
                                                  SkyliveUsers.lingua==unicode(language),
                                                  SkyliveUsers.citta==unicode(city)), limit=limit, offset=offset))


   elif dest == 'users':
      ret = []
      for user in ulist.replace(" ", "").split(","):
         ret.append(store.findFirst(SkyliveUsers, SkyliveUsers.username==unicode(user)))
   return ret

def getSubscribed():
   return list((store.query((UserSubscriptions, SkyliveUsers), UserSubscriptions.username==SkyliveUsers.username)))
