from twisted.application import service
from twisted.internet import defer, reactor, task, protocol, threads
import clientproto, lx200proto, webgui, ircbot, httptunnel
from utils.genutils import configFile
from utils import mail

from lang import lang
import signal, logging, sys
import observatory
from decra.ephemer import Ephem
import ephem
from Database import utils as dbutils
log = logging.getLogger( 'SkylivedCore' )

import traceback

expiremsg_it="""

Se ti fa piacere, puoi continuare a sostenere il progetto e avere in cambio
il controllo remoto dei telescopi per un altro anno.

Visita il sito web http://www.skylive.it per conoscere le quote
di abbonamento aggiornate!

Se ti servono altre informazioni, siamo a disposizione,

Lo staff Skylive
www.skylive.it

"""

expiremsg_en="""

If you like , you can continue to use the remote controlled telescopes for
another year and support the Skylive Project.

Please visit our web site at http://www.skylive.it to know 
the updated yearly fees.

Feel free to contact us if you need more information.

The Skylive Team.
www.skylive.it

"""

silencedtelescope="""
Sorry, the telescope public chat is temporarely disabled.
Please send a private message to one of the 
skylive staff members (people with the nickname starting
with a !)

Spiacenti, la chat pubblica del telescopio e' momentaneamente
disabilitata. Mandate un messaggio a un membro dello staff di 
skylive (le persone con un ! davanti al nickname)
"""

class skylivedService(service.Service):

   def __init__(self, *args, **kwargs):
      log.info('Initializing Core')
      signal.signal(signal.SIGHUP, self.receivedHUP)
      signal.signal(signal.SIGTERM, self.receivedTERM)
      signal.signal(signal.SIGINT, self.receivedINT)
      self.curdir=kwargs['curdir']
      sys.path.append(self.curdir+"/skyliveDaemon")
      log.debug('Current dir: '+self.curdir)
      self.dbActions = 0
      self.dbCron = task.LoopingCall(self.dbCronCall)
      self.dbCron.start(60)

      self.clientcfg = configFile(self.curdir+'/conf/chatserver.conf')
      self.clientcfg.readConfig()
      self.telescopecfg = configFile(self.curdir+'/conf/telescopi.conf')
      self.telescopecfg.readConfig()
      self.observatorycfg = configFile(self.curdir+'/conf/osservatori.conf')
      self.observatorycfg.readConfig()
      self.telescopes = {}
      self.clients = {}
      self.ccall = {}
      self.stars = []
      self.doubles = []
      self.maxclientslog = 0
      try:
         f = open(self.curdir+'/conf/stelle.list')
         for line in f:
            self.stars.append(line.replace("\r", "").replace("\n", ""))
         f.close()
      except:
         pass
      try:
         f = open(self.curdir+'/conf/doppie.list')
         for line in f:
            self.doubles.append(line.replace("\r", "").replace("\n", ""))
         f.close()
      except:
         pass
      self.getObservatoryes()
      for telescope in self.telescopecfg.sections():
         num = self.telescopecfg.get(telescope, 'number')
         self.telescopes[num] = self.telescopecfg.getOptions(telescope)
         self.addTelescopeToObservatory(num)
         self.setTelescopeDefaults(num)
         self.telescopes[num]['cronreserved'] = False
         self.telescopes[num]['clients'] = {}
         self.telescopes[num]['name'] = telescope
         self.telescopes[num]['photostatus'] = False
         self.telescopes[num]['expstatus'] = 'none'
         self.telescopes[num]['currentobj'] = 'Unknown'
         self.telescopes[num]['started'] = False
         self.telescopes[num]['guideXerr'] = '0'
         self.telescopes[num]['guideYerr'] = '0'
         self.telescopes[num]['movereceived'] = False
         self.telescopes[num]['lastaz'] = False
         self.telescopes[num]['liveuri'] = 'low'
         self.telescopes[num]['rescron'] = task.LoopingCall(self.telescopeCronCall, num)
         self.telescopes[num]['rescron'].start(60)
         self.makeTelescopeReservations(num)
         self.setTelescopeDecra(num)
      self.parent.__init__(self, *args)


   def dbCronCall(self):
      # XXX TODO:
      # cose come la scadenza di una subscription dovrebbe lanciare un evento
      # che cambi i permessi all'utente!
      log.debug("DB CRON EVENT STARTED")
      
      if self.dbActions <= 0:
         log.debug('GO WITH CHECKS FOR DBACTIONS')
         self.checkCloseExpirationStart()
         self.cleanUserSubscriptionStart()
         self.cleanUserHoursStart()
         self.assignMountlyHoursStart()
      else:
         log.debug('DBACTIONS '+str(self.dbActions))


   def telescopeCronCall(self, tnum):
      log.debug("Telescope CRON EVENT STARTED FOR TELESCOPE "+str(tnum))
      # Becca reservation ancora in GOING ma scadute, e nel caso svuola la
      # cronreserved e via di makereservation
      resv = dbutils.getBookingNow(tnum)
      self.telescopes[tnum]['cronreserved'] = False
      if resv and len(resv) > 0:
         cronreserved = resv.allowedusers.append(resv.username)
         if self.telescopes[tnum]['reservedlist']:
            reservedlist = self.telescopes[tnum]['reservedlist']
            cronadd = filter(lambda x,cronreserved=reservedlist:not x in reservedlist, cronreserved)
            if len(cronadd) > 0:
               self.telescopes[tnum]['cronreserved'] = cronadd
               self.makeTelescopeReservations(tnum)
         else:
            self.telescopes[tnum]['cronreserved'] = cronreserved
            self.makeTelescopeReservations(tnum)
         if resv.result == unicode('NOTYET'):
            resv.setGoing()

         # Poi bisogna beccare lo stato del tele e infilarlo in good / bad

   def assignMountlyHoursStart(self):
      self.dbActionPlus("assignMountlyHoursRoutine")
      reactor.callLater(0.1, self.assignMountlyHoursRoutine)

   def assignMountlyHoursRoutine(self):
      log.debug("assignMountlyHoursRoutine")
      try:
         assigned = dbutils.assignMountlyHours()
         if assigned:
            reactor.callLater(0.1, self.assignMountlyHoursRoutine)
         else:
            self.dbActionLess("assignMountlyHoursRoutine")
      except:
         log.debug("ERRORE IN assignMountlyHoursRoutine")
         for i in traceback.format_exc().splitlines():
            log.debug("ERRORE IN assignMountlyHoursRoutine "+str(i))
         self.dbActionLess("assignMountlyHoursRoutine")


   def checkCloseExpirationStart(self):
      self.dbActionPlus("checkCloseExpirationRoutine")
      reactor.callLater(0.1, self.checkCloseExpirationRoutine)

   

   def checkCloseExpirationRoutine(self):
      log.debug("checkCloseExpirationRoutine")
      user, expiring = dbutils.checkCloseExpirationSubs()
      if expiring and user:
         log.info("CLOSE EXPIRATION FOR USER "+str(user.username))
         try:
            m = mail.TextEmail()
            m.SetTo(str(user.email))

            m.SetCc("info@skylive.it")
            m.SetReply("info@skylive.it")
            if str(user.nazione).lower() in ['italy', 'it','italiano','italia','italiana']:
               m.SetFrom("account_it@astronomix.org")
               m.SetSubject("Il tuo abbonamento a SkyLive sta per scadere!")
               strmsg="Ciao %s,\n\n" % str(user.nome)
               strmsg+="Il tuo abbonamento a SkyLive per il controllo remoto dei telescopi\n"
               strmsg+="di tipo \"%s\" " % str(expiring.subname)
               strmsg+="scadra' il %s. \n\n" % str(expiring.expiration.asHumanly())
               strmsg+=expiremsg_it
            else:
               m.SetFrom("account_en@astronomix.org")
               m.SetSubject("Your skylive account is expiring soon!")
               strmsg="Hello %s,\n\n" % str(user.nome)
               strmsg+="Your SkyLive account for the control of the remote telescopes\n"
               strmsg+="of the type \"%s\" " % str(expiring.subname)
               strmsg+="will expire at %s. \n\n" % str(expiring.expiration.asHumanly())
               strmsg+=expiremsg_en
            m.SetMsg(strmsg)
            #reactor.callInThread(m.Send)
            m.Send()
         except:
            log.debug("ERRORE ADVISING FOR CLOSE EXPIRATION USER "+str(user.username))
            for i in traceback.format_exc().splitlines():
               log.debug("ERRORE IN ADVISING "+str(i))

         reactor.callLater(0.1, self.checkCloseExpirationRoutine)
      else:
         self.dbActionLess("checkCloseExpirationRoutine")


   def cleanUserSubscriptionStart(self):
      self.dbActionPlus("cleanUserSubscriptionRoutine")
      reactor.callLater(0.1, self.cleanUserSubscriptionRoutine)

   def cleanUserSubscriptionRoutine(self):
      log.debug("cleanUserSubscriptionRoutine")
      try:
         removed = dbutils.cleanExpiredSubscriptionsOne()
      except:
         log.debug("ERRORE GRAVE IN cleanUserSubscriptionRoutine ")
         for i in traceback.format_exc().splitlines():
            log.debug("ERRORE GRAVE IN cleanUserSubscriptionRoutine "+str(i))
         removed = False
      if removed:
         log.info("REMOVED SUBSCRIPTIONS FOR "+str(removed.username))
         try:
            user=dbutils.getOneUser(removed.username)
            if user:
               m = mail.TextEmail()
               m.SetTo(str(user.email))
               m.SetFrom("Skylive <robot.skylive@astronomix.org>")
               m.SetCc("info@skylive.it")
               m.SetReply("info@skylive.it")
               if str(user.nazione).lower() in ['italy', 'it','italiano','italia','italiana']:
                  m.SetSubject("Il tuo abbonamento a SkyLive e' scaduto!")
                  strmsg="Ciao %s,\n\n" % str(user.nome)
                  strmsg+="Il tuo abbonamento a SkyLive per il controllo remoto dei telescopi\n"
                  strmsg+="di tipo \"%s\" " % str(removed.subname)
                  strmsg+="e' scaduto il %s. \n\n" % str(removed.expiration.asHumanly())
                  strmsg+=expiremsg_it
               else:
                  m.SetSubject("Your skylive account is expired!")
                  strmsg="Hello %s,\n\n" % str(user.nome)
                  strmsg+="Your SkyLive account for the control of the remote telescopes\n"
                  strmsg+="of the type \"%s\" " % str(removed.subname)
                  strmsg+="is expired at %s. \n\n" % str(removed.expiration.asHumanly())
                  strmsg+=expiremsg_en
               m.SetMsg(strmsg)
               #reactor.callInThread(m.Send)
               m.Send()
         except:
            log.debug("ERRORE REMOVING SUBSCRIPTION FOR "+str(removed.username)+" "+traceback.format_exc())
         # XXX aggiorniamo lo stato dell'utente?
         reactor.callLater(0.1, self.cleanUserSubscriptionRoutine)
      else:
         self.dbActionLess("cleanUserSubscriptionRoutine")


   def cleanUserHoursStart(self):
      self.dbActionPlus("cleanUserHoursRoutine")
      reactor.callLater(0.1, self.cleanUserHoursRoutine)

   def cleanUserHoursRoutine(self):
      log.debug("cleanUserHoursRoutine")
      try:
         removed = dbutils.cleanUserHoursOne()
         if removed:
            reactor.callLater(0.1, self.cleanUserHoursRoutine)
         else:
            self.dbActionLess("cleanUserHoursRoutine")
      except:
         log.debug("ERRORE IN cleanUserHoursRoutine "+traceback.format_exc())
         #self.dbActions = self.dbActions-1
         self.dbActionLess("cleanUserHoursRoutine")

   def dbActionPlus(self, who="UNKNOWN"):
      log.debug("DBACTION PLUS "+str(who))
      self.dbActions+=1
      log.debug("DBACTION NOW "+str(self.dbActions))

   def dbActionLess(self, who="UNKNOWN"):
      log.debug("DBACTION LESS "+str(who))
      self.dbActions-=1
      log.debug("DBACTION NOW "+str(self.dbActions))
      
   def endLongDbCalls(self, result=None):
      self.dbActions = 0


   def makeTelescopeReservations(self, num):
      try:
         self.telescopes[num]['reservedlist'] = False
         reserved = self.telescopes[num]['reserved']
         if len(reserved) > 0 and reserved != 'no':
            self.telescopes[num]['reservedlist'] = reserved.split(',')
         cronreserved = self.telescopes[num]['cronreserved']
         if cronreserved and len(cronreserved) > 0 and cronreserved != 'no':
            if self.telescopes[num]['reservedlist']:
               self.telescopes[num]['reservedlist']+cronreserved
            else:
               self.telescopes[num]['reservedlist'] = cronreserved
      except:
         self.telescopes[num]['reservedlist'] = False
      self.updateUserListString(num).addCallback(lambda _: 'Updating userlist')

   def updateUserListString(self, num):
      for ruser in self.telescopes[num]['clients'].keys():
         cuser = ruser.replace("~", "")
         if self.telescopes[num]['reservedlist']:
            if cuser in self.telescopes[num]['reservedlist']:
               self.telescopes[num]['clients'][ruser] = '>'+ruser
            else:
               if self.telescopes[num]['clients'][ruser][:1] == '>':
                  self.Clients_on_delFromTelescopeList(num, user=ruser)
                  self.Clients_on_putInTelescopeList(num, user=ruser)
         else:
            if self.telescopes[num]['clients'][ruser][:1] == '>':
               self.Clients_on_delFromTelescopeList(num, user=ruser)
               self.Clients_on_putInTelescopeList(num, user=ruser)
      return defer.succeed(True)

   def stopReactor(self, result=None):
      reactor.stop()
      log.debug("REACTOR STOPPED")

   def receivedTERM(self, signum, frame):
      self.receivedINT(signum, frame)

   def receivedINT(self, signum, frame):
      log.info('STOPPING REACTOR')
      reactor.callLater(1, self.stopReactor)

   def receivedHUP(self, signum, frame):
      log.info("Received HUP: reloading config files")
      self.clientcfg.readConfig()
      self.telescopecfg.readConfig()
      self.observatorycfg.readConfig()
      for telescope in self.telescopecfg.sections():
         num = self.telescopecfg.get(telescope, 'number')
         confs = self.telescopecfg.getOptions(telescope)
         for key in confs:
            self.telescopes[num][key] = confs[key]

         tconfs = self.telescopes[num]
         if 'clients' not in tconfs.keys():
            self.telescopes[num]['clients'] = {}
         if 'liveuri' not in tconfs.keys():
            self.telescopes[num]['liveuri'] = 'low'
         self.checkTelescopeLiveUris(num, force=True)
         if 'status' not in tconfs.keys():
            self.setTelescopeDefaults(num)
         if 'name' not in tconfs.keys():
            self.telescopes[num]['name'] = telescope
         if 'photostatus' not in tconfs.keys():
            self.telescopes[num]['photostatus'] = False
         if 'expstatus' not in tconfs.keys():
            self.telescopes[num]['expstatus'] = 'none'
         if 'timeout' not in tconfs.keys():
            self.telescopes[num]['timeout'] = 240
         if 'currentobj' not in tconfs.keys():
            self.telescopes[num]['currentobj'] = 'Unknown'
         if 'started' not in tconfs.keys():
            self.telescopes[num]['started'] = False
         if 'guideXerr' not in tconfs.keys():
            self.telescopes[num]['guideXerr'] = '0'
         if 'guideYerr' not in tconfs.keys():
            self.telescopes[num]['guideYerr'] = '0'
         status = 'offline'
         if 'cronreserved' not in tconfs.keys():
            self.telescopes[num]['cronreserved'] = False

         try:
            if self.telescopes[num]['connected']:
               status = 'online'
         except:
            pass
         self.makeTelescopeReservations(num)
         if self.telescopes[num]['started']:
            self.SETCCDTemperature(num, self.telescopes[num]['setccdtemp'])
         self.Telescope_on_setStatus(status, tnum=num)
         self.setTelescopeDecra(num)
         self.Clients_on_broadcastTelescopeList(num)
         self.Clients_on_broadcastTelescopeData(num
               ).addCallback(lambda _: "Broadcasting TelescopeData on tel "+str(num))
         log.debug('Reloaded telescope '+num)
      try:
         self.observatory.reloadConfig().addCallback(lambda _: "Reloaded Observatory Object")
      except:
         pass


   def checkTelescopeLiveUris(self, num, user=False, force=False):
      log.debug("checkTelescopeLiveUris  "+str(num)+" "+str(user)+" "+str(force))
      try:
         nclients = len(self.telescopes[num]['clients'].keys())
         if nclients > 0:
            limit = int(self.telescopes[num]['lowhightlimit'])
            if nclients >= limit and self.telescopes[num]['liveuri'] == 'low':
               log.debug("Change limit to high "+str(num))
               self.telescopes[num]['liveuri'] = 'high'
               self.Clients_on_broadcastTelescopeLiveUri(num)

            elif nclients < limit and self.telescopes[num]['liveuri'] != 'low':
               log.debug("Change limit to low "+str(num))
               self.telescopes[num]['liveuri'] = 'low'
               self.Clients_on_broadcastTelescopeLiveUri(num)
            else:
               if force:
                  log.debug("Change limit forced "+str(num))
                  self.Clients_on_broadcastTelescopeLiveUri(num)
               elif user:
                  log.debug("Change for user "+str(user))
                  self.Clients_on_sendTelescopeLiveUri(num, user=user)
         else:
            self.telescopes[num]['liveuri'] = 'low'
      except:
         log.debug('Error in checkTelescopeLiveUris %s' % str(num))

   def setTelescopeDecra(self, num):
      log.debug("Setting DecRa for telescope "+str(num))
      try:
         obs = self.telescopes[num]['observatory']
         lon = self.observatorycfg.get(obs, 'longitude')
         lat = self.observatorycfg.get(obs, 'latitude')
         self.telescopes[num]['ephem'] = Ephem(lon, lat, obs.upper())
         log.debug(self.telescopes[num]['ephem'])
      except:
         log.debug("Can't SET Ephem on telescope "+str(num))

   def SETCCDTemperature(self, num, temp):
      log.debug("Setting CCD Temperature to "+str(temp)+" for telescope "+str(num))
      try:
         self.telescopes[num]['connection'].on_sendSETCCDTemp(temp)
      except:
         log.debug("Failed setting temperature for telescope "+str(num))

   def setTelescopeDefaults(self, tnum):
      if self.telescopes[tnum]['useforcestatus'] in ['yes', 'true']:
         stat = 'force'
      else:
         stat = 'offline'
      self.telescopes[tnum]['status'] = self.telescopes[tnum][stat+'status']
      self.telescopes[tnum]['coordinate'] = '00:00:0-00.00'
      self.telescopes[tnum]['CCDtemp'] = '-00,0000'
      

   def getClientFactory(self):
      f = clientproto.OldClientFactory()
      f.cfg = self.clientcfg
      f.setConfig()
      f.clients = self.clients
      f.telescopes = self.telescopes
      f.command = self.on_CommandFromClient
      return f

   def getLx200Factory(self):
      f = lx200proto.lx200Factory()
      f.cfg = self.telescopecfg
      f.setConfig()
      f.telescopes = self.telescopes
      f.command = self.on_CommandFromTelescopes
      return f

   def getShellFactory(self):
      from twisted.manhole.telnet import ShellFactory
      f = ShellFactory()
      f.service = self
      return f

   def getWebGui(self):
      f = webgui.createResource(self.on_CommandFromWebgui)
      return f

   def getHTTPTunnelServer(self):
      return httptunnel.HTTPTunnelServer(self.on_CommandFromWebgui)

   def getIrcBot(self, nick, password, channels):
      f = protocol.ReconnectingClientFactory()
      f.protocol,f.nickname,f.getUser = ircbot.IrcBotProtocol, nick, nick
      f.channels = channels
      f.password = password
      f.command = self.on_CommandFromIRCBot
      return f


   def getObservatoryes(self):
      self.observatory = observatory.Observatory(self)
      self.observatory.command = self.on_CommandFromObservatory
      self.observatory.initialize()

   def on_CommandFromObservatory(self, command, *args, **kwargs):
      log.debug("CommandFromObservatory: "+str(command)+" "+str(args))
      cmd = command.keys()[0]
      try:
         observ=command[cmd][1]
      except:
         observ='UNKNOWN'
      try:
         arg=command[cmd][0]
      except:
         arg=command[cmd]
      return self.on_callback('Observatory', cmd, arg, obs=observ)

   def on_CommandFromClient(self, username, command, *args, **kwargs):
      kwargs['user'] = username
      return self.on_callback('Clients', command, *args, **kwargs)

   def on_CommandFromTelescopes(self, tnum, command, *args, **kwargs):
      kwargs['tnum'] = tnum
      return self.on_callback('Telescope', command, *args, **kwargs)

   def on_CommandFromWebgui(self, command, *args, **kwargs):
      log.debug("Commad from WebGUI")
      return self.on_callback('Webgui', command, *args, **kwargs)

   def on_CommandFromIRCBot(self, command, *args, **kwargs):
      log.debug("Command from IRCBot")
      return self.on_callback('IRCBot', command, *args, **kwargs)

   def on_callback(self, who, cmd, *args, **kwargs):
      log.debug("CALLBACK: %s on %s, args: %s, kwargs: %s" % (who, cmd, str(args), str(kwargs)))
      f=getattr(self, who+'_on_'+cmd, None)
      if f and callable(f):
         return f(*args, **kwargs)

   def broadcastUserMessage(self, command, userlist, *args):
      for user in userlist:
         try:
            f = getattr(self.clients[user]['connection'], 'on_'+command, None)
            if f and callable(f):
               f(*args)
         except:
            import traceback
            traceback.print_exc(file=sys.stdout)
            erstr = str(command)+" "+str(userlist)+" "+str(args)+" " #+str(err)
            log.warning("broadCastUserMessage FAILED!!! "+erstr)
      return defer.succeed(True)



   def startCronPhoto(self, tnum, exp, filter, bin, name):
      if not tnum in self.ccall.keys():
         self.ccall[tnum] = {}
         self.ccall[tnum]['timer'] = task.LoopingCall(self.cronCalls, tnum)
         self.ccall[tnum]['data'] = [int(exp), filter, bin, int(exp), name]
         self.ccall[tnum]['timer'].start(1.0)
         self.telescopes[tnum]['expstatus'] = 'exposing'
         log.debug("self.Clients_on_broadcastExposureStatus in startCronPhoto")
         self.Clients_on_broadcastExposureStatus(tnum)

   def cronCalls(self, tnum):
      try:
         rem = int(self.ccall[tnum]['data'][0])
         filter  = self.ccall[tnum]['data'][1]
         bin = self.ccall[tnum]['data'][2]
         texp = int(self.ccall[tnum]['data'][3])
         name = self.ccall[tnum]['data'][4]
         if rem > 0:
            self.ccall[tnum]['timeout'] = int(int(self.telescopes[tnum]['timeout'])/int(bin))
            pstr="Foto *%s* tot exp: %d sec., filtro: %s, bin: %s, Rimangono: %d sec. - " % (name, texp, filter, bin, rem)
            pstr=pstr + "Photo *%s* tot exp: %d sec., filter: %s, bin: %s, ETA: %d sec." % (name, texp, filter, bin, rem)
            self.telescopes[tnum]['photostatus'] = pstr
            self.telescopes[tnum]['expstatus'] = 'exposing'
            self.ccall[tnum]['data'][0] = rem-1
         else:
            if self.telescopes[tnum]['expstatus'] != 'uploading':
               self.telescopes[tnum]['expstatus'] = 'uploading'
               self.Clients_on_broadcastExposureStatus(tnum)

            if self.ccall[tnum]['timeout'] > 0:
               self.telescopes[tnum]['expstatus'] = 'uploading'
               timeout = self.ccall[tnum]['timeout']
               log.debug("Timeout: "+str(timeout))
               pstr="Attesa invio foto *%s* tot exp: %d sec., filtro: %s, bin: %s ..." % (name, texp, filter, bin)
               pstr=pstr+" - Uploading photo *%s* tot exp: %d sec., filter: %s, bin: %s ..." % (name, texp, filter, bin)
               self.telescopes[tnum]['photostatus'] = pstr
               self.ccall[tnum]['timeout']=timeout-1
            else:
               log.debug("Calling Stop CronPhoto")
               self.stopCronPhoto(tnum)
      except:
         pass

   def stopCronPhoto(self, tnum):
      log.debug("Stop CRON Telescope "+str(tnum))
      stopped = False
      try:
         self.ccall[tnum]['timer'].stop()
         del self.ccall[tnum]
      except:
         pass
      try:
         if self.telescopes[tnum]['photostatus']:
            stopped = True
            self.telescopes[tnum]['photostatus'] = False
      except:
         pass
      try:
         self.telescopes[tnum]['expstatus'] = 'none'
         self.Clients_on_broadcastExposureStatus(tnum)
      except:
         pass
      try:
         if stopped:
            userlist = self.telescopes[tnum]['clients'].keys()
            self.broadcastUserMessage('sendPhotoYes', userlist, True
                  ).addCallback(lambda _: 'PhotoYes '+tnum+' Userlist broadcasted')
      except:
         pass

   def addTelescopeToObservatory(self, tnum):
      obs = self.telescopes[tnum]['observatory']
      log.debug("Add telescope "+str(tnum)+" to observatory "+obs)
      self.observatory.AddTel(tnum, obs)

   def getAutoEphem(self, username, tnum, cmd, descr):
      log.debug("AutoEphem Called")
      try:
         log.debug("Trying get ephem for "+str(username)+" on telescope "+str(tnum)+", cmd "+str(cmd)+" and descr "+str(descr))
         ep = self.telescopes[tnum]['ephem'].queryDecra(cmd)
         log.debug("AUTOEPHEM for "+str(descr)+":"+str(ep))
         if ep:
            ra = ep[0]
            dec = ep[1]
            self.Clients_on_TelescopeMoveARDEC(tnum, ra, dec, user=username, desc=descr)
      except:
         log.debug("AUTOEPHEM ERROR")

   ##### OBSERVATORY COMMANDS ###############

   def Observatory_on_setWhetherStatus(self, *args, **kwargs):
      log.info("Setting weather status for telescopes"+str(args[0]))
      obs = kwargs['obs']
      tlist = args[0]
      for t in tlist:
         self.Clients_on_broadcastWheather(t)

   def Observatory_on_setDomeStatus(self, *args, **kwargs):
      log.info("Setting dome status for telescopes"+str(args[0]))
      obs = kwargs['obs']
      tlist = args[0]
      for t in tlist:
         self.Clients_on_broadcastDome(t)

   def Observatory_on_getRoof(self, *args, **kwargs):
      try:
         tel=args[0]
         r = self.telescopes[tel]['connection'].roof
         log.info("NOW Calling getRoof for telescope "+tel+" ("+str(r)+")")
         return self.telescopes[tel]['connection'].roof
      except:
         log.debug("getRoof Failed")
         return None

   ##### TELESCOPE COMMANDS #################

   def Telescope_on_setDefault(self, *args, **kwargs):
      if len(args) == 0:
         try:
            args.append(kwargs['tnum'])
         except:
            pass
      if len(args) > 0:
         self.setTelescopeDefaults(args[0])

   def Telescope_on_sendPhotoNo(self, *args, **kwargs):
      tnum = kwargs['tnum']
      try:
         userlist = self.telescopes[tnum]['clients'].keys()
         self.broadcastUserMessage('sendPhotoNo', userlist, True
               ).addCallback(lambda _: 'PhotoNo '+tnum+' Userlist broadcasted')
         try:
            if self.telescopes[tnum]['photoweb'] == '0':
               self.Telescope_on_photoIsEnd(tnum=tnum)
         except:
            pass
      except:
         pass

   def Telescope_on_photoIsEnd(self, *args, **kwargs):
      try:
         self.stopCronPhoto(kwargs['tnum'])
      except:
         pass

   def Telescope_on_setStatus(self, *args, **kwargs):
      log.info("Setting status for telescope "+kwargs['tnum']+" ("+args[0]+")")
      if self.telescopes[kwargs['tnum']]['useforcestatus'] in ['yes', 'true']:
         stat = 'force'
      else:
         stat = args[0]
      self.telescopes[kwargs['tnum']]['status'] = self.telescopes[kwargs['tnum']][stat+'status']
      if args[0] == 'offline':
         self.telescopes[kwargs['tnum']]['coordinate'] = '00:00:0-00.00'
         self.telescopes[kwargs['tnum']]['CCDtemp'] = '-00,0000'
         self.telescopes[kwargs['tnum']]['started'] = False
         self.Clients_on_broadcastTelescopeOnOff(kwargs['tnum'])
         try:
            log.debug("RECEIVED AN OFFLINE STATUS ON TELESCOPE "+str(kwargs['tnum'])+", TRYING TO SET IT AS UNAUTH")
            self.telescopes[kwargs['tnum']]['connection'].state = 'UNAUTH'
            self.telescopes[kwargs['tnum']]['connection'].logged = False
            self.telescopes[kwargs['tnum']]['connection'].askForAuth()
         except:
            pass
      try:
         self.telescopes[kwargs['tnum']]['connection'].connstatus = stat
      except:
         pass
      try:
         if self.telescopes[kwargs['tnum']]['connection'].is_focusing:
            self.telescopes[kwargs['tnum']]['status'] = 'Autofocus in corso... - Autofocus running...'
         if self.telescopes[kwargs['tnum']]['connection'].is_synching:
            self.telescopes[kwargs['tnum']]['status'] = 'Sync in corso... - Sync running...'
      except:
         pass
      log.info("Setting status for telescope "+kwargs['tnum']+" ("+stat+")")


   def Telescope_on_setCOORDINATE(self, *args, **kwargs):
      self.telescopes[kwargs['tnum']]['coordinate'] = args[0].replace('\xdf', '.')
      try:
         if self.telescopes[kwargs['tnum']]['connected']:
            if self.telescopes[kwargs['tnum']]['started']:
               try:
                  if self.telescopes[kwargs['tnum']]['meridianprotection'] in ['yes', 'true']:
                     if self.telescopes[kwargs['tnum']]['connection'].canAcceptCommand():
                        coord = self.telescopes[kwargs['tnum']]['coordinate']
                        if not coord in ['00:00:0-00.00', '00:00:0+00.00']:
                           curaz = self.getAzFromARDEC(coord, kwargs['tnum'])
                           if curaz:
                              if not self.telescopes[kwargs['tnum']]['lastaz']:
                                 self.telescopes[kwargs['tnum']]['lastaz'] = curaz
                              else:
                                 lastaz = self.telescopes[kwargs['tnum']]['lastaz']
                                 self.telescopes[kwargs['tnum']]['lastaz'] = curaz
                                 cpos = False
                                 lpos = False
                                 cneg = False
                                 lneg = False
                                 if int(curaz) in range(0,11): cpos = True
                                 if int(curaz) in range(350,361): cneg = True
                                 if int(lastaz) in range(0,11): lpos = True
                                 if int(lastaz) in range(350,361): lneg = True
                                 if (cpos and lneg) or (cneg and lpos):
                                    log.debug("Telescope "+str(kwargs['tnum'])+" is transit over meridian!!")
                                    curobj = self.telescopes[kwargs['tnum']]['currentobj']
                                    self.Clients_on_TelescopeMoveARDEC(
                                       kwargs['tnum'], coord[:7], coord[7:], user='MeridianProtection', desc=curobj)

                                 cpos = False
                                 lpos = False
                                 cneg = False
                                 lneg = False
                                 if int(curaz) in range(180,190): cpos = True
                                 if int(curaz) in range(170,180): cneg = True
                                 if int(lastaz) in range(180,190): lpos = True
                                 if int(lastaz) in range(170,180): lneg = True
                                 if (cpos and lneg) or (cneg and lpos):
                                    log.debug("Telescope "+str(kwargs['tnum'])+" is transit over anti-meridian!!")
                                    curobj = self.telescopes[kwargs['tnum']]['currentobj']
                                    self.Clients_on_TelescopeMoveARDEC(
                                       kwargs['tnum'], coord[:7], coord[7:], user='MeridianProtection', desc=curobj)


                     else:
                        self.telescopes[kwargs['tnum']]['lastaz'] = False
               except:
                  self.telescopes[kwargs['tnum']]['lastaz'] = False
      except:
         pass

   def getAzFromARDEC(self, coord, tnum):
      try:
         ra = coord[:7]
         dec = coord[7:]
         ep = self.telescopes[tnum]['ephem'].getALTAZbyRADEC(ra, dec)
         az = str(ephem.degrees(ep['az']))
         log.debug("Azimut coord for telescope "+str(tnum)+": "+az)
         azs = az.split(":")
         return azs[0]
      except:
         log.debug("Azimut coord for telescope "+str(tnum)+": ERROR!!!")
         return False


   def Telescope_on_setCCDTEMP(self, *args, **kwargs):
      self.telescopes[kwargs['tnum']]['CCDtemp'] = args[0]

   def Telescope_on_setConnection(self, *args, **kwargs):
      self.telescopes[kwargs['tnum']]['connected'] = args[0][0]
      self.telescopes[kwargs['tnum']]['connection'] = args[0][1]

   def Telescope_on_setObject(self, *args, **kwargs):
      log.debug("Setting object to "+args[0]+" for telescope "+str(kwargs['tnum']))
      try:
         old = self.telescopes[kwargs['tnum']]['currentobj']
      except:
         pass
      self.telescopes[kwargs['tnum']]['currentobj'] = args[0]
      if old != self.telescopes[kwargs['tnum']]['currentobj']:
         self.Clients_on_broadcastObject(kwargs['tnum'])

   def Telescope_on_setGuideError(self, *args, **kwargs):
      tnum = kwargs['tnum']
      try:
         self.telescopes[kwargs['tnum']]['guideXerr'] = args[0][0]
         self.telescopes[kwargs['tnum']]['guideYerr'] = args[0][1]
      except:
         pass
      try:
         userlist = self.telescopes[tnum]['clients'].keys()
         self.broadcastUserMessage('sendGuideErr', userlist, args[0][0], args[0][1]
               ).addCallback(lambda _: 'Guide Errors on Telescope '+tnum+' broadcasted')
      except:
         pass


   def Telescope_on_setTelescopeStarted(self, *args, **kwargs):
      if args[0]:
         log.debug("Telescope "+str(kwargs['tnum'])+" started")
         self.telescopes[kwargs['tnum']]['started'] = True
         self.SETCCDTemperature(kwargs['tnum'], self.telescopes[kwargs['tnum']]['setccdtemp'])
      else:
         log.debug("Telescope "+str(kwargs['tnum'])+" stopped")
         self.telescopes[kwargs['tnum']]['started'] = False
      self.Clients_on_broadcastTelescopeOnOff(kwargs['tnum'])

   def Telescope_on_setAutoFocus(self, *args, **kwargs):
      if args[0]:
         log.debug("Telescope "+str(kwargs['tnum'])+" AutoFocus Started")
      else:
         log.debug("Telescope "+str(kwargs['tnum'])+" AutoFocus Stopped")
      try:
         status = self.telescopes[kwargs['tnum']]['connection'].connstatus
         self.Telescope_on_setStatus(status, tnum=kwargs['tnum']) 
         status = self.telescopes[kwargs['tnum']]['status']
         userlist = self.telescopes[kwargs['tnum']]['clients'].keys()
         coordinates = self.telescopes[kwargs['tnum']]['coordinate']
         self.broadcastUserMessage('sendStatus', userlist, status, coordinates
            ).addCallback(lambda _: "Moving status broadcasted")
      except:
         pass

   
   def Telescope_on_setSynching(self, *args, **kwargs):
      if args[0]:
         log.debug("Telescope "+str(kwargs['tnum'])+" Synching Started")
      else:
         log.debug("Telescope "+str(kwargs['tnum'])+" Synching Stopped")
      try:
         status = self.telescopes[kwargs['tnum']]['connection'].connstatus
         self.Telescope_on_setStatus(status, tnum=kwargs['tnum'])
         status = self.telescopes[kwargs['tnum']]['status']
         userlist = self.telescopes[kwargs['tnum']]['clients'].keys()
         coordinates = self.telescopes[kwargs['tnum']]['coordinate']
         self.broadcastUserMessage('sendStatus', userlist, status, coordinates
            ).addCallback(lambda _: "Moving status broadcasted")
      except:
         pass

   def Telescope_on_settingFWHM(self, *args, **kwargs):
      # XXX TRUE
      log.debug("setFWHM "+str(args)+" "+str(kwargs))
      if args[0]:
         try:
            userlist = self.telescopes[kwargs['tnum']]['clients'].keys()
            self.broadcastUserMessage('sendFWHM', userlist, str(args[0])
               ).addCallback(lambda _: "sending FWHM")
         except:
            log.debug("I can't send FWHM status to %s for telescope %s!" % (kwargs['user'], str(args[0])))



   ############ CLIENTS COMMANDS ###############

   def Clients_on_isDuplicatedRequest(self, *args, **kwargs):
      if kwargs['user'] in self.clients.keys():
         ouid = self.clients[kwargs['user']]['connection'].uid
         if ouid == args[0]:
            return True
      return False

   def Clients_on_checkMaxClient(self, *args, **kwargs):
      mc = int(self.clientcfg.get("general", "maxclient"))
      nowclients = len(self.clients.keys())
      log.info("Clients now:  "+str(nowclients))
      if nowclients > self.maxclientslog:
         self.maxclientslog=nowclients
         log.info("Maximum Client: "+str(nowclients))
      if nowclients >= mc:
         if nowclients-mc >= 10:
            return 'High'
         else:
            return 'Low'
      return False

   def Clients_on_isSecondClient(self, *args, **kwargs):
      if kwargs['user'] in self.clients.keys():
         return True
      else:
         return False

   def Clients_on_setUserConnection(self, *args, **kwargs):
      log.debug("Setting user connection for "+kwargs['user'])
      try:
         self.clients[kwargs['user']]['connection'] = args[0]
      except:
         self.clients[kwargs['user']] = {}
         self.clients[kwargs['user']]['connection'] = args[0]

   def Clients_on_removeUser(self, *args, **kwargs):
      try:
         del self.clients[kwargs['user']]
      except:
         pass

   def Clients_on_getTelescopeStatus(self, *args, **kwargs):
      try:
         coordinates = self.telescopes[args[0]]['coordinate']
         status = self.telescopes[args[0]]['status']
         temp = self.telescopes[args[0]]['CCDtemp']
      except:
         coordinates, status, temp = '00:00:0-00.00', 'Telescopio sconosciuto - Unknown telescope', '-00,0000'
      return coordinates, status, temp

   def Clients_on_sendTelescopeOnOff(self, *args, **kwargs):
      status = "OFF"
      try:
         user = kwargs['user']
         try:
            if self.telescopes[args[0]]['started']:
               status = "ON"
         except:
            pass
         try:
            self.clients[user]['connection'].on_sendTelescopeOnOff(status)
         except:
            pass
      except:
         pass

   def Clients_on_sendTelescopeLiveUri(self, *args, **kwargs):
      try:
         num = args[0]
         user = kwargs['user']
         if self.telescopes[num]['liveuri'] == 'low':
            turi = self.telescopes[num]['lowliveguide'].replace(" ","").split(',')
            tint = str(self.telescopes[num]['lowliveguideint'])
         else:
            turi = self.telescopes[num]['highliveguide'].replace(" ","").split(',')
            tint = str(self.telescopes[num]['highliveguideint'])
         self.clients[user]['connection'].sendTelescopeLiveUri(turi, tint)

      except:
         log.debug("Errore in Clients_on_sendTelescopeLiveUri")

   def Clients_on_sendTelescopeBinning(self, *args, **kwargs):
      try:
         user = kwargs['user']
         binlist = args[1]
         self.clients[user]['connection'].sendTeleBinning(binlist)
      except:
         pass

   def Clients_on_getPhotoRun(self, *args, **kwargs):
      tnum = args[0]
      try:
         if self.telescopes[tnum]['photostatus']:
            return True
         else:
            return False
      except:
         return False

   def Clients_on_getIsTeleFree(self, *args, **kwargs):
      user = kwargs['user']
      ret = False
      try:
      #if True:
         reslist = self.telescopes[args[0]]['reservedlist']
         if not reslist:
            reslist = []
         strcompare = user
         if strcompare[:1] == '~':
            strcompare = user[1:]
         if (not self.telescopes[args[0]]['photostatus']) \
         and (((len(reslist) > 0) and (strcompare in reslist)) or True) \
         and self.telescopes[args[0]]['connected'] \
         and self.telescopes[args[0]]['started']:
            if self.telescopes[args[0]]['connection'].canAcceptCommand():
               log.debug("Telescope %s is free" % str(args[0]))
               ret = True

         # XXX Some debugs!
         log.debug('PHOTOSTATUS: '+str(self.telescopes[args[0]]['photostatus']))
         log.debug('CONNECTED: '+str(self.telescopes[args[0]]['connected']))
         log.debug('STARTED: '+str(self.telescopes[args[0]]['started']))
         try:
            log.debug('CANACCEPTCOMMAND: '+str(self.telescopes[args[0]]['connection'].canAcceptCommand()))
         except:
            pass

      except:
         log.debug("TelescopeIsFree Error")
      if not ret:
         log.debug("Telescope %s is NOT free!" % str(args[0]))
      return ret

   def Clients_on_isPhotoRunning(self, *args, **kwargs):
      log.debug("getIsPhotoRunning by "+str(kwargs['user']))
      user = kwargs['user']
      tel = args[0]
      if int(args[0]) != 0:
         if not self.Clients_on_getPhotoRun(str(tel)):
            log.debug("getIsPhotoRunning by "+user+" is PhotoYES")
            self.broadcastUserMessage('sendPhotoYes', [user], True
                                    ).addCallback(lambda _: 'PhotoYes '+str(tel)+' Userlist broadcasted')
         else:
            log.debug("getIsPhotoRunning by "+user+" is PhotoNO")

         
   def Clients_on_AdminCommand(self, *args, **kwargs):
      log.debug("REQUESTING ADMIN: "+str(args)+str(kwargs))
      try:
         if self.clients[kwargs['user']]['connection'].perms['general']['admin']:
            kwargs['admin'] = kwargs['user']
            try:
               cmd = args[0]
               if len(args) > 1:
                  arg = args[1:]
               else:
                  arg = []
               f  = getattr(self, 'Admin_on_'+cmd, None)
            except:
               cmd = args[0][0]
               if len(args[0]) > 1:
                  arg = args[0][1:]
               else:
                  arg = []
               f  = getattr(self, 'Admin_on_'+cmd, None)

            if f and callable(f):
               return f(*arg, **kwargs)
      except:
         pass


   def Clients_on_getTelescopePhotoStatus(self, *args, **kwargs):
      try:
         coordinates = self.telescopes[args[0]]['coordinate']
         temp = self.telescopes[args[0]]['CCDtemp']
         status = str(self.telescopes[args[0]]['photostatus'])
      except:
         coordinates, status, temp = '00:00:0-00.00', 'Telescopio sconosciuto - Unknown telescope', '-00,0000'
      return coordinates, status, temp


   def Clients_on_putInTelescopeList(self, *args, **kwargs):
      try:
         if not kwargs['user'] in self.telescopes[args[0]]['clients'].keys():
            struser = kwargs['user']
            log.debug(self.clients[kwargs['user']]['connection'].perms)
            try:
               if self.clients[kwargs['user']]['connection'].perms['general']['admin']:
                  struser = '!'+kwargs['user']
               elif self.clients[kwargs['user']]['connection'].perms[args[0]]['canset']:
                  struser = '@'+kwargs['user']
               try:
                  reslist = self.telescopes[args[0]]['reservedlist']
                  strcompare = kwargs['user']
                  if kwargs['user'][:1] == '~':
                     strcompare = kwargs['user'][1:]
                  if reslist and strcompare in reslist:
                     struser = '>'+kwargs['user']
               except:
                  pass
            except:
               pass
            self.telescopes[args[0]]['clients'][kwargs['user']] = struser
            self.Clients_on_broadcastTelescopeList(args[0])
            self.checkTelescopeLiveUris(args[0], kwargs['user'])
            self.Clients_on_sendTelescopeData(args[0], user=kwargs['user'])
            self.Clients_on_sendExposureStatus(args[0], user=kwargs['user'])
      except:
         pass

   def Clients_on_delFromTelescopeList(self, *args, **kwargs):
      try: 
         if kwargs['user'] in self.telescopes[args[0]]['clients'].keys():
            del self.telescopes[args[0]]['clients'][kwargs['user']]
            self.checkTelescopeLiveUris(args[0])
            self.Clients_on_broadcastTelescopeList(args[0])
      except:
         pass

   def Clients_on_broadcastTelescopeList(self, *args, **kwargs):
      tnum = args[0]
      users = self.telescopes[tnum]['clients'].values()
      users.sort()
      userlist = self.telescopes[tnum]['clients'].keys()
      # this can be a long and blocking operation if we have many clients
      # on the telescope, so, launch it in a deferred 
      self.broadcastUserMessage('sendUserList', userlist, users
            ).addCallback(lambda _: 'Telescope '+tnum+' Userlist broadcasted')

   def Clients_on_sendExposureStatus(self, *args, **kwargs):
      log.debug("Clients_on_sendExposureStatus"+str(args)+str(kwargs))
      username  = kwargs['user']
      tnum = args[0]
      dataok = False
      try:
         if self.telescopes[tnum]['expstatus'] in ['exposing','uploading']:
            if tnum in self.ccall.keys():
               if 'data' in self.ccall[tnum].keys():
                  dataok = True
                  rem = self.ccall[tnum]['data'][0]
                  filter = self.ccall[tnum]['data'][1]
                  bin = self.ccall[tnum]['data'][2]
                  exp = self.ccall[tnum]['data'][3]
                  nick = self.ccall[tnum]['data'][4]

         if kwargs['user'] in self.telescopes[tnum]['clients'].keys():
            if self.telescopes[tnum]['expstatus'] == 'exposing':
               if dataok:
                  self.clients[username]['connection'].sendExposureRunning(rem, filter, bin, exp, nick)
            elif  self.telescopes[tnum]['expstatus'] == 'uploading':
               if dataok:
                  self.clients[username]['connection'].sendExposureUpload(rem, filter, bin, exp, nick)
            else:
               self.clients[username]['connection'].sendExposureNone()

      except:
         pass

   def Clients_on_sendTelescopeData(self, *args, **kwargs):
      userlist = [kwargs['user']]
      username = kwargs['user']
      tnum = args[0]
      try:
         if kwargs['user'] in self.telescopes[args[0]]['clients'].keys():
            lat = 'Unknown'
            lon = 'Unknown'
            try:
               obs = self.telescopes[tnum]['observatory']
            except:
               obs = 'Unknown'
            if obs != 'Unknown' and obs != '':
               try:
                  lon = self.observatorycfg.get(obs, 'longitude')
                  lat = self.observatorycfg.get(obs, 'latitude')
               except:
                  pass
            tname = self.telescopes[tnum]['model']
            ccdname = self.telescopes[tnum]['ccd']
            filters = self.telescopes[tnum]['filters']
            fov = self.telescopes[tnum]['fov']
            focal = self.telescopes[tnum]['focal']
            #binning = range(int(self.telescopes[tnum]['frombin']), int(self.telescopes[tnum]['tobin'])+1)
            #binlist = ",".join([str(i) for i in binning])
            binlist = self.telescopes[tnum]['bin'].replace(" ", "")
            self.broadcastUserMessage('sendLONLAT', userlist, lon, lat
                                      ).addCallback(lambda _: "Geographics coordinates send to %s" % username)
            self.broadcastUserMessage('sendTelescopeFeatures', userlist, tname, ccdname, filters, fov, focal
                                      ).addCallback(lambda _: "Geographics coordinates send to %s" % username)
            self.Clients_on_sendDome(tnum, user=username)
            self.Clients_on_sendObject(tnum, user=username)
            self.Clients_on_sendWheather(tnum, user=username)
            self.Clients_on_sendTelescopeOnOff(tnum, user=username)
            self.Clients_on_sendTelescopeBinning(tnum, binlist, user=username)
            self.Clients_on_sendStreamingUri(tnum, user=username)
            try:
               fwhm = self.telescopes[tnum]['connection'].fwhm
            except:
               fwhm = '0,00'
            self.broadcastUserMessage('sendFWHM', userlist, fwhm
                                       ).addCallback(lambda _: "send FWHM to %s" %username)
      except:
         pass


   def Clients_on_sendStreamingUri(self, *args, **kwargs):
      tnum = args[0]
      userlist = [kwargs['user']]
      username = kwargs['user']
      if self.telescopes[tnum]['enablestreaming'] in ['yes', 'YES', 'si', 'SI', 'true', 'force']:
         streamuri = self.telescopes[tnum]['streaminguri']
      else:
         streamuri = 'NONE'
      try:
         if kwargs['user'] in self.telescopes[tnum]['clients'].keys():
            if self.telescopes[tnum]['enablestreaming'] == 'force':
               self.broadcastUserMessage('sendForceStreaming', userlist, streamuri).addErrback(lambda _: "Errore Stream")
            else:
               self.broadcastUserMessage('sendStreaming', userlist, streamuri).addErrback(lambda _: "Errore Stream")
      except:
         log.debug("I can't send StreamingURI status to %s for telescope %s!" % (kwargs['user'], str(args[0])))


   def Clients_on_sendDome(self, *args, **kwargs):
      tnum = args[0]
      try:
         dome = self.observatory.observatoryes[self.telescopes[tnum]['observatory']]['domeobj'].status
      except:
         dome = 'Error'
      userlist = [kwargs['user']]
      username = kwargs['user']
      try:
         if kwargs['user'] in self.telescopes[tnum]['clients'].keys():
            self.broadcastUserMessage('sendDome', userlist, dome).addErrback(lambda _: "Errore nel Dome")
      except:
         log.debug("I can't send Dome status to %s for telescope %s!" % (kwargs['user'], str(args[0])))

   def Clients_on_sendWheather(self, *args, **kwargs):
      tnum = args[0]
      try:
         wheather = self.observatory.observatoryes[self.telescopes[tnum]['observatory']]['wheatherobj'].status
      except:
         wheather = 'Error'
      userlist = [kwargs['user']]
      username = kwargs['user']
      try:
         if kwargs['user'] in self.telescopes[args[0]]['clients'].keys():
            self.broadcastUserMessage('sendWheather', userlist, wheather).addErrback(lambda _: "Errore nel Wheather")
      except:
         log.debug("I can't send Wheater status to %s for telescope %s!" % (kwargs['user'], str(args[0])))

   def Clients_on_sendObject(self, *args, **kwargs):
      tnum = args[0]
      try:
         object = self.telescopes[tnum]['currentobj']
      except:
         object = 'Unknown'
      userlist = [kwargs['user']]
      username = kwargs['user']
      try:
         if kwargs['user'] in self.telescopes[args[0]]['clients'].keys():
            self.broadcastUserMessage('sendObject', userlist, object).addErrback(lambda _: "Errore nell' Object")
      except:
         pass

   def Clients_on_broadcastTelescopeData(self, *args, **kwargs):
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendTelescopeData(tnum, user=username)
      return defer.succeed(True)

   def Clients_on_broadcastExposureStatus(self, *args, **kwargs):
      log.debug("Exposure Status BROADCAST")
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendExposureStatus(tnum, user=username)
      return defer.succeed(True)

   def Clients_on_broadcastTelescopeOnOff(self, *args, **kwargs):
      log.debug("Broadcast Telescope OnOff")
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendTelescopeOnOff(tnum, user=username)
      return defer.succeed(True)

   def Clients_on_broadcastTelescopeLiveUri(self, *args, **kwargs):
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendTelescopeLiveUri(tnum, user=username)
      return defer.succeed(True)

   def Clients_on_broadcastObject(self, *args, **kwargs):
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendObject(tnum, user=username)
      return defer.succeed(True)

   def Clients_on_broadcastDome(self, *args, **kwargs):
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendDome(tnum, user=username)
      return defer.succeed(True)

   def Clients_on_broadcastWheather(self, *args, **kwargs):
      tnum = args[0]
      userlist = self.telescopes[tnum]['clients'].keys()
      for username in userlist:
         self.Clients_on_sendWheather(tnum, user=username)
      return defer.succeed(True)


   def Clients_on_ChatMessageForTelescope(self, *args, **kwargs):
      tnum = args[0]
      user = kwargs['user']
      if not self.telescopes[tnum]['silenced'].lower() in ['yes', 'true'] \
            and kwargs['user'][0] not in '!' or '>':
         msg = args[1]
         userlist = self.telescopes[tnum]['clients'].keys()
         self.broadcastUserMessage('sendChatMessage', userlist, msg, user 
               ).addCallback(lambda _: 'Telescope '+tnum+' MSGTOALL broadcasted')
      else:
         self.clients[user]['connection'].on_sendPrivMessage(silencedtelescope, 'SkyliveServer')

   def Clients_on_PrivMsg(self, *args, **kwargs):
      user = kwargs['user']
      msg = args[0][1]
      to = args[0][0]
      try:
         if to in self.clients.keys():
            self.clients[to]['connection'].on_sendPrivMessage(msg, user)
      except:
         pass

   def Clients_on_getTelescopeWhiteLists(self, *args, **kwargs):
      ruser = kwargs['user']
      dellist = ['~','@','!','>']
      user = ruser
      if ruser[:1] in dellist:
         user = user[1:]
      user = user.replace("~", "")
      for telescope in self.telescopes.keys():
         try:
            if user in self.telescopes[telescope]['whitelist'].replace(" ", "").split(','):
               wl = self.telescopes[telescope]['whitelist']
               log.debug("Whitelist for telescope "+telescope+": "+wl)
               try:
                  self.clients[ruser]['connection'].perms[telescope]['canset'] = True
               except:
                  self.clients[ruser]['connection'].perms[telescope] = {'canset': True}
         except:
            pass

######
# Start moving commands for telescopes


   def Clients_on_TelescopeMoveCARDINAL(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      where = args[1]
      userlist = self.telescopes[tnum]['clients'].keys()
      try:
         if self.telescopes[tnum]['connected'] and not self.telescopes[tnum]['photostatus']:
            self.telescopes[tnum]['connection'].on_sendMoveCARDINAL(where)
            coordinates = self.telescopes[tnum]['coordinate']
            status = user+' muove a '+where+' - '+user+' move to '+lang.it2en(where)
            self.broadcastUserMessage('sendStatus', userlist, status, coordinates
                  ).addCallback(lambda _: "Moving status broadcasted")
            self.telescopes[tnum]['lastaz'] = False
      except:
         pass

   def Clients_on_TelescopeMovePlanets(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      code = args[1]
      name = args[2]
      cmd = args[3]
      userlist = self.telescopes[tnum]['clients'].keys()
      try:
         if self.telescopes[tnum]['connected'] and not self.telescopes[tnum]['photostatus']:
            if self.telescopes[tnum]['useautoephem'] not in  ['yes', 'true']:
               log.debug("Telescope "+str(tnum)+" don't need autoephem")
               self.telescopes[tnum]['connection'].on_sendMovePlanets(code, name)
               coordinates = self.telescopes[tnum]['coordinate']
               status = user+' punta '+name+' - '+user+' point to '+name
               self.broadcastUserMessage('sendStatus', userlist, status, coordinates
                     ).addCallback(lambda _: "Moving status broadcasted")
            else:
               log.debug("Telescope "+str(tnum)+" need autoephem")
               self.getAutoEphem(user, tnum, cmd, name)     
            self.telescopes[tnum]['lastaz'] = False
      except:
         pass

   def Clients_on_TelescopeMoveARDEC(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      ar = args[1]
      dec = args[2]
      desc = False
      if 'desc' in kwargs.keys():
         desc = kwargs['desc']
      userlist = self.telescopes[tnum]['clients'].keys()
      try:
         if self.telescopes[tnum]['connected'] and not self.telescopes[tnum]['photostatus']:
            self.telescopes[tnum]['connection'].on_sendMoveARDEC(ar, dec, desc)
            coordinates = self.telescopes[tnum]['coordinate']
            status = user+' punta AR:'+ar+' DEC:'+dec+' - '+user+' point to RA'+ar+' DEC:'+dec
            if desc:
               status = user+' punta '+desc+' - '+user+' point to '+desc
            self.broadcastUserMessage('sendStatus', userlist, status, coordinates
                  ).addCallback(lambda _: "Moving status broadcasted")
            self.telescopes[tnum]['lastaz'] = False
      except:
         pass

   def Clients_on_TelescopeMoveMessier(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      messier = args[1]
      cmd = args[2]
      userlist = self.telescopes[tnum]['clients'].keys()
      try:
         if self.telescopes[tnum]['connected'] and not self.telescopes[tnum]['photostatus']:
            if self.telescopes[tnum]['useautoephem'] not in ['yes', 'true']:
               log.debug("Telescope "+str(tnum)+" don't need autoephem")
               self.telescopes[tnum]['connection'].on_sendMoveMessier(messier)
               coordinates = self.telescopes[tnum]['coordinate']
               status = user+' punta '+messier+' - '+user+' point to '+messier
               self.broadcastUserMessage('sendStatus', userlist, status, coordinates
                     ).addCallback(lambda _: "Moving status broadcasted")
            else:
               log.debug("Telescope "+str(tnum)+" need autoephem")
               self.getAutoEphem(user, tnum, cmd, messier)
            self.telescopes[tnum]['lastaz'] = False
      except:
         pass

   def Clients_on_TelescopeMoveCngc(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      cngc = args[1]
      cmd = args[2]
      userlist = self.telescopes[tnum]['clients'].keys()
      try:
         if self.telescopes[tnum]['connected'] and not self.telescopes[tnum]['photostatus']:
            if self.telescopes[tnum]['useautoephem'] not in ['yes', 'true']:
               log.debug("Telescope "+str(tnum)+" don't need autoephem")
               self.telescopes[tnum]['connection'].on_sendMoveCngc(cngc)
               coordinates = self.telescopes[tnum]['coordinate']
               status = user+' punta '+cngc+' - '+user+' point to '+cngc
               self.broadcastUserMessage('sendStatus', userlist, status, coordinates
                     ).addCallback(lambda _: "Moving status broadcasted")
            else:
               log.debug("Telescope "+str(tnum)+" need autoephem")
               self.getAutoEphem(user, tnum, cmd, cngc)
            self.telescopes[tnum]['lastaz'] = False
      except:
         pass

   def Clients_on_TelescopeCenter(self, *args, **kwargs):
      log.debug("TELESCOPES: "+str(self.telescopes.keys()))
      user = kwargs['user']
      tnum = args[0]
      center = args[1]
      userlist = self.telescopes[tnum]['clients'].keys()
      try:
         if self.telescopes[tnum]['connected'] and not self.telescopes[tnum]['photostatus']:
            self.telescopes[tnum]['connection'].on_sendCenter(center)
            coordinates = self.telescopes[tnum]['coordinate']
            status = user+' Centra '+center+' - '+user+' Center '+center
            self.broadcastUserMessage('sendStatus', userlist, status, coordinates
                  ).addCallback(lambda _: "Center status broadcasted")
            self.telescopes[tnum]['lastaz'] = False
      except:
         pass

# End Telescope moving commands
#####################


   def Clients_on_TelescopeMakePhoto(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      exp = args[1]
      codestr = args[2]
      try:
         bin = codestr[2]
      except:
         bin = 3

      try:
         web = codestr[-1]
      except:
         web = '1'

      self.telescopes[tnum]['photoweb'] = web
         
      log.debug(str(user)+" has requested PHOTO of exp "+str(exp)+" on tnum "+str(tnum)+" with codestr "+str(codestr))
      try:
         if exp == '000':
            log.debug("Aborted 0 exposure photo request")
         elif not self.telescopes[tnum]['photostatus'] or exp == '001':
            #if int(bin) >= int(self.telescopes[tnum]['frombin']) and int(bin) <= int(self.telescopes[tnum]['tobin']):
            if str(bin) in self.telescopes[tnum]['bin'].replace(" ", "").replace(",",""):
               self.telescopes[tnum]['connection'].on_makePhoto(exp, codestr, user)
               if self.telescopes[tnum]['photostatus'] and exp =='001':
                  self.stopCronPhoto(tnum)
               else:
                  self.startCronPhoto(tnum, exp, codestr[:1], codestr[:3][2:], user)
            else:
               #frombin = self.telescopes[tnum]['frombin']
               #tobin = self.telescopes[tnum]['tobin']
               binlist =  self.telescopes[tnum]['bin']
               self.clients[user]['connection'].on_sendErroneusBinning(binlist, bin)

      except:
         pass

   def Clients_on_focusAuto(self, *args, **kwargs):
      user = kwargs['user']
      tnum = self.clients[user]['connection'].tnum
      try:
         self.telescopes[tnum]['connection'].on_autoFocus()
      except:
         pass


   def Clients_on_livePointer(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      try:
         x = args[1]
         userlist = self.telescopes[tnum]['clients'].keys()
         y = args[2]
         if self.clients[user]['connection'].perms['general']['admin']:
            self.broadcastUserMessage('sendLivePointer', userlist, x, y
                  ).addCallback(lambda _: "Live Pointer broadcasted")
      except:
         pass


   def Clients_on_getMeteoUrl(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      try:
         self.clients[user]['connection'].on_sendMeteoUrl(self.telescopes[tnum]['meteo'])
      except:
         pass

   def Clients_on_TelescopeIsReserved(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      try:
         return self.telescopes[tnum]['reservedlist']
      except:
         return False

   def Clients_on_Telescope_ReserverIsHere(self, *args, **kwargs):
      user = kwargs['user']
      tnum = args[0]
      try:
         reservedlist = self.telescopes[tnum]['reservedlist']
         userlist = self.telescopes[tnum]['clients'].keys()
         for ruser in reservedlist:
            if ruser in userlist or '~'+ruser in userlist:
               return True
         return False
      except:
         return False

   def Clients_on_getNumTelescopes(self, *args, **kwargs):
      return str(len(self.telescopes.keys()))

   def Clients_on_getStarList(self, *args, **kwargs):
      return self.stars

   def Clients_on_getDoubleList(self, *args, **kwargs):
      return self.doubles

   ############# COMMANDS FROM ADMINS ####################

   def Admin_on_stopClient(self, *args, **kwargs):
      try:
         user = args[0]
         self.clients[user]['connection'].on_sendStop()
      except:
         pass

   def Admin_on_focusPlus(self, *args, **kwargs):
      log.debug("Requesting FOCUSPLUS")
      user = kwargs['admin']
      tnum = self.clients[user]['connection'].tnum
      try:
         self.telescopes[tnum]['connection'].on_focusPlus()
      except:
         pass

   def Admin_on_focusLess(self, *args, **kwargs):
      log.debug("Requesting FOCUSLESS")
      user = kwargs['admin']
      tnum = self.clients[user]['connection'].tnum
      try:
         self.telescopes[tnum]['connection'].on_focusLess()
      except:
         pass

   def Admin_on_sync(self, *args, **kwargs):
      log.debug("Requesting SYNC")
      user = kwargs['admin']
      tnum = self.clients[user]['connection'].tnum
      try:
         self.telescopes[tnum]['connection'].on_sync()
      except:
         pass

   ############# COMMANDS FROM WEBGUI ####################

   def Webgui_on_EnterTelescope(self, *args, **kwargs):
      log.debug('ENTERTELESCOPE '+str(args)+' '+str(kwargs))
      self.Clients_on_putInTelescopeList(*args, **kwargs)


   def Webgui_on_exitTelescope(self, *args, **kwargs):
      log.debug('EXITTELESCOPE '+str(args)+' '+str(kwargs))
      self.Clients_on_delFromTelescopeList(*args, **kwargs)


   def Webgui_on_getUserList(self, tnum, user, *args, **kwargs):
      users = self.telescopes[tnum]['clients'].values()
      users.sort()
      self.broadcastUserMessage('sendUserList', [user], users
            ).addCallback(lambda _: 'Telescope '+tnum+' Userlist fired to '+user)



   def Webgui_on_sendChat(self, dest, msg, user):
      # XXX This is a crude hack and it will work only
      # for the first 9 telescopes!
      if str(dest).isdigit():
         return self.Clients_on_ChatMessageForTelescope(str(dest), str(msg), user=user)
      else:
         return self.Clients_on_PrivMsg([str(dest), str(msg)], user=user)


   def Webgui_on_setUserConnection(self, *args, **kwargs):
      return self.Clients_on_setUserConnection(*args, **kwargs)



   def Webgui_on_UserList(self, *args, **kwargs):
      return self.clients.keys()

   def Webgui_on_UserNum(self, *args, **kwargs):
      log.debug(self.clients.keys())
      return str(len(self.clients.keys()))

   def Webgui_on_GetTelescopes(self, *args, **kwargs):
      return self.telescopes

   def Webgui_on_GetTelescopeConfig(self, *args, **kwargs):
      return self.telescopecfg

   def Webgui_on_UserReg(self, *args, **kwargs):
      return str(dbutils.getRegUserNum())

   def Webgui_on_GetObservatoryesConfig(self, *args, **kwargs):
      log.debug(self.observatorycfg)
      return self.observatorycfg

   def Webgui_on_ReloadTelConfig(self, *args, **kwargs):
      self.receivedHUP(False, False)
      return True

   def Webgui_on_getUserData(self, *args, **kwargs):
      try:
         return self.clients[args[0]]
      except:
         return False

   def Webgui_on_EmailMessage(self, msg, msghtml, mtype, sub, dest, language, ulist, city, mlist=True):
      offset = 0
      limit = 3
      reactor.callLater(0.6, self.nowSendEmail, offset, limit, msg, msghtml, mtype, sub, dest, language, ulist, city, mlist)


   def nowSendEmail(self, offset, limit, msg, msghtml, mtype, subject, dest, language, ulist, city, mlist=True):
      log.warning("CALLED nowSendMail offset "+str(offset)+" limit "+str(limit))
      err = False
      retdb = True
      msgok = True
      try:
         ret = dbutils.nowSendEmail(offset, limit, dest, language, ulist, city)
      except: 
         log.debug("ERRORE EMAIL QUERY")
         ret = []
         retdb = False
         err = True
      try:
         msg = unicode(msg).encode('iso-8859-16', 'ignore')
         #msg = unicode(msg).encode('utf8', 'ignore')
      except:
         log.debug("ERRORE EMAIL UNICODE")
         msgok = False
         err = True
      
      for uentry in ret:
         try:
            log.info("SENDING EMAIL TO: "+str(unicode(uentry.email).encode('ascii', 'ignore')))
            log.info("USERNAME: "+str(unicode(uentry.username).encode('ascii', 'ignore')))
            log.info("SEQUENCE: "+str(offset)+" OF LIMIT "+str(limit))

            rmsg = msg.replace("[NOME]", unicode(uentry.nome).encode('utf8', 'ignore'))
            rmsg = rmsg.replace("[COGNOME]", unicode(uentry.cognome).encode('utf8', 'ignore'))
            rmsg = rmsg.replace("[USERNAME]", unicode(uentry.username).encode('utf8', 'ignore'))
            rmsg = rmsg.replace("[PASSWORD]", unicode(uentry.password).encode('utf8', 'ignore'))

            rhmsg = msghtml.replace("[NOME]", unicode(uentry.nome).encode('utf8', 'ignore'))
            rhmsg = rhmsg.replace("[COGNOME]", unicode(uentry.cognome).encode('utf8', 'ignore'))
            rhmsg = rhmsg.replace("[USERNAME]", unicode(uentry.username).encode('utf8', 'ignore'))
            rhmsg = rhmsg.replace("[PASSWORD]", unicode(uentry.password).encode('utf8', 'ignore'))

            if (uentry.mlist and mlist) or (not mlist):
               destinazione = unicode(uentry.email).encode('ascii', 'ignore')
               if mtype=='text':
                  m = mail.TextEmail()
               else:
                  m = mail.HTMLEmail()
               m.SetTo(str(destinazione))
               m.SetFrom("Skylive <robot.skylive@astronomix.org>")
               m.SetReply("info@skylive.it")
               m.SetSubject(subject)
               if mtype=='text':
                  m.SetMsg(rmsg)
               else:
                  m.SetTextMsg(rmsg)
                  m.SetHtmlMsg(rhmsg)
               #reactor.callInThread(m.Send)
               #if int(offset) > 1377:
               m.Send()
         except:
            log.debug("ERRORE EMAIL ALL'OFFSET "+str(offset)+", limit "+str(limit)+" -> "+what)
            m = mail.TextEmail()
            m.SetTo("nextime@nexlab.it")
            m.SetFrom("Skylive <robot.skylive@astronomix.org>")
            m.SetReply("info@skylive.it")
            m.SetSubject("ERRORE EMAIL SKYLIVE (except) "+traceback.format_exc())
            m.SetMsg("ERRORE ALL'OFFSET "+str(offset)+", limit "+str(limit))
            #reactor.callInThread(m.Send)
            #m.Send()

      if (len(ret) >= limit):
         offset = offset + limit
         reactor.callLater(0.6, self.nowSendEmail, offset, limit, msg, msghtml, mtype, subject, dest, language, ulist, city, mlist)
      if err:
         if not msgok:
            what = 'MSGOK'
         elif not retdb:
            what = 'RETDB'
         else:
            what = 'UNKNOWN'
         try:
            m = mail.TextEmail()
            m.SetTo("nextime@nexlab.it")
            m.SetFrom("Skylive <robot.skylive@astronomix.org>")
            m.SetReply("info@skylive.it")
            m.SetSubject("ERRORE EMAIL SKYLIVE")
            m.SetMsg("ERRORE ALL'OFFSET "+str(offset)+", limit "+str(limit)+" -> "+what)
            #reactor.callInThread(m.Send)
            #m.Send()
         except:
            log.debug("ERRORE NELL'ERRORE EMAIL!!!")


   def Webgui_on_citiesList(self, *args, **kwargs):
      return  dbutils.getCities()


   def Webgui_on_GlobalMessage(self, *args, **kwargs):
      try:
         tipo=args[0] 
         mitt=args[1] 
         msg=args[2]
         dest=args[3]
         w=args[4]
         h=args[5]
         globaldest=args[6]
         if globaldest:
            if dest == 'all':
               userlist = self.clients.keys()
            else:
               try:
                  userlist = self.telescopes[dest]['clients'].keys()
               except:
                  try:
                     userlist = self.telescopes[int(dest)]['clients'].keys()
                  except:
                     userlist = []
         else:
            userlist = dest.replace(" ", "").split(",")

         log.debug("GLOBAL MESSAGE FOR USERS: "+str(userlist))

         if tipo == 'text':
            self.broadcastUserMessage('sendPrivMessage', userlist, msg, mitt
                                     ).addCallback(lambda _: 'Global Text Message broadcasted')
         elif tipo == 'link':
            self.broadcastUserMessage('sendOpenLink', userlist, msg, mitt
                                     ).addCallback(lambda _: 'Global Text Message broadcasted')
         elif tipo == 'live':
            self.broadcastUserMessage('sendBigLive', userlist
                                     ).addCallback(lambda _: 'Global Text Message broadcasted')
         else:
            self.broadcastUserMessage('sendHtmlMessage', userlist, msg, mitt, w, h
                                     ).addCallback(lambda _: 'Global Html Message broadcasted')

      except:
         log.debug("Error trying to compose a Global message")

   def Webgui_on_killUserData(self, *args, **kwargs):
      try:
         log.debug("KILLUSERDATA"+str(args))
         log.debug("KILLUSER: "+args[0]['connection'].username)
         tnum = args[0]['connection'].tnum
         self.Clients_on_delFromTelescopeList(tnum, user=args[0]['connection'].username)
         del self.clients[args[0]['connection'].username]  
      except:
         pass
