"""
     Copyright (C) 2007-2009 Franco Lanza <nextime@nexlab.it>
     Copyright (C) 2007-2009 Sandro Aliano <ita595@hotmail.com>
     Copyright (C) 2007-2009 Ivan Bellia <skylive@skylive.it>

     Web site: http://www.astronomix.org/trac/Skylive-NG

     This file is part of Skylive-NG.

     Skylive-NG is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.

     Skylive-NG is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with Skylive-NG.  If not, see <http://www.gnu.org/licenses/>.
"""


import wx
import platform
from twisted.protocols.basic import LineReceiver
import time

VERSION="156"

class ProtoParser:

   def __init__(self):
      self.separator="#^#"
      self.terminator="\r\n"

   def ParseTelescopeConf(self, str):
      tscope = {}
      exploded = self._explode(str)
      tscope["model"] = exploded[0]
      tscope["focal"] = exploded[1]
      tscope["field"] = exploded[2]
      tscope["ccd"] = exploded[3]
      tscope["filters"] = exploded[4]
      tscope["BOH"] = exploded[5]
      tscope["archiveurl"] = exploded[6]
      tscope["statusurl"] = exploded[7]
      return tscope

   def ParseConfigList(self, filecont):
      return filecont.replace("\r", "").split("*\n")

   def ParseLX200CatalogFromSkylive(self, catlist):
      res = {}
      for entry in catlist:
         res[entry.replace(entry[len(entry)-4:], '')]=entry.replace(entry[:len(entry)-4], '')
      return res

   def parseCommand(self, string):
      expl = self._explode(string)
      args = []
      for arg in expl[2:]:
         args.append(arg)
      return {'cmd': expl[1], 'args': args, 'from': expl[0]}


   def _explode(self, string):
      return string.split(self.separator)

class ServerComm:

   def __init__(self, parent):
      self._parent = parent
      self.parser = ProtoParser()
      self.separator = self.parser.separator

   def AuthString(self, user="", pwd=""):
      self.user = user
      self.pwd = pwd
      self.msginit = self.user + self.separator + self.pwd + self.separator

   def ParseServerMsg(self, msg):
      #print msg
      cmd = self.parser.parseCommand(msg)
      ret = False
      ret2 = False
      if cmd['cmd'] == 'Autorizzazione':
         if cmd['args'][0] == 'NonTrovato':
            ret = {'AuthFromServer': None}
         else:
            ret = {'AuthFromServer': True}

         if cmd['args'][1] == 'Admin':
            self._parent.on_skyClientCommand('setAdminPriv', 'Admin')
         
      elif cmd['cmd'] == 'UserList':
         ret = {'updateUserList': cmd['args'][0].split("*!*")}
      elif cmd['cmd'] == 'YourName':
         ret = {'setMyUsername': cmd['args'][0]}
      elif cmd['cmd'] == 'ChatMessage':
         ret = {'incomingChat': [cmd['from'], cmd['args'][0]]}
      elif cmd['cmd'] == 'OpenWebLink':
         ret = {'incomingWebLink': [cmd['args'][0]]}
      elif cmd['cmd'] == 'BigLive':
         ret = {'incomingBigLive': True}
      elif cmd['cmd'] == 'Messaggio':
         ret = {'incomingPrivChat': [cmd['from'], cmd['args'][0]]}
      elif cmd['cmd'] == 'HtmlMessage': 
         ret = {'incomingHtmlMessage': [cmd['from'], cmd['args'][0], cmd['args'][1], cmd['args'][2]]}
      elif cmd['cmd'] == 'Status':
         try:
            ret = {'statusMessageFromServer': [cmd['args'][0].split("**")[0], 
                                               cmd['args'][0].split("**")[1].split("+")[0], 
                                               "+"+cmd['args'][0].split("**")[1].split("+")[1]]}
            #ret2 = ret
         except:
            ret = {'statusMessageFromServer': [cmd['args'][0].split("**")[0],
                                               cmd['args'][0].split("**")[1].split("-")[0],
                                               "-"+cmd['args'][0].split("**")[1].split("-")[1]]}
            #ret2 = ret
      elif cmd['cmd'] == 'CCDTEMP':
         ret = {'CCDTemp': cmd['args'][0]}
      elif cmd['cmd'] == 'PhotoReadyNO':
         # This message shuld be generated when an exposition is 
         # terminated and the file is to be uploaded to the web server
         ret = {'photoStatus': 'notReady'}
         ret2 = ret

      elif cmd['cmd'] == 'PhotoReadyYES':
         # when we get this message the photo is ready to be downloaded
         ret = {'photoStatus': 'Ready'}
         ret2 = ret
         
      elif cmd['cmd'] == 'RequestData':
         ret = {'requestData': True}
      #to fit new server messages the follow strings
      elif cmd['cmd'] == 'TelescopeFeat':
         ret = {'telescopeFeat': cmd['args'][0]}
      
      elif cmd['cmd'] == 'Dome':
         ret = {'domeStatus' : cmd['args'][0]}
         
      elif cmd['cmd'] == 'Wheather':
         ret = {'rainStatus' : cmd['args'][0]}
         
      elif cmd['cmd'] == 'Object':
         ret = {'objName' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'Ping':
         ret = {'PingReq' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'LonLat':
         ret = {'LonLat' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'availableStars':
         ret = {'setStars' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'availableDoubles':
         ret = {'setDoubles' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'GuideError':
         ret = {'setError' : [cmd['args'][0], cmd['args'][1]]}
      
      elif cmd['cmd'] == 'NTel':
         ret = {'setTscopeCombo' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'setCross':
         ret = {'activeCicerone' : [cmd['args'][0], cmd['args'][1]]}
      
      elif cmd['cmd'] == 'TeleON':
         ret = {'TeleLink' : 'TeleON'}
         ret2 = ret
      
      elif cmd['cmd'] == 'TeleOFF':
         ret = {'TeleLink' : 'TeleOFF'}
         ret2 = ret
      
      elif cmd['cmd'] == 'TeleFree':
         ret2 = {'TeleStatus' : 'Free'}
      
      elif cmd['cmd'] == 'TeleBusy':
         ret2 = {'TeleStatus' : 'Busy'}
      
      elif cmd['cmd'] == 'TeleBinning':
         ret = {'setBins' : cmd['args'][0]}
      
      elif cmd['cmd'] == 'StopClient':
         ret = {'StopClient': True}

      elif cmd['cmd'] == 'TelescopeLiveUri':
         ret = {'setTelescopeLiveUri': [cmd['args'][0].split("**"), cmd['args'][1]]}

      elif cmd['cmd'] ==  'ExposureNone':
         ret = {'setExposureNone': True}
      elif cmd['cmd'] == 'ExposureUpload':
         ret = {'setExposureUpload': [cmd['args'][1]]+cmd['args'][0].split("**")}

      elif cmd['cmd'] == 'ExposureRunning':
         ret = {'setExposureRunning': [cmd['args'][1]]+cmd['args'][0].split("**")}
      elif cmd['cmd'] == 'setFWHM':
         ret = {'setFWHM': cmd['args'][0]}

      elif cmd['cmd'] == 'Streaming':
         ret = {'Streaming': cmd['args'][0]}

      elif cmd['cmd'] == 'ForceStreaming':
         ret = {'ForceStreaming': cmd['args'][0]}

      #end new messages

      if ret:
         self._parent.on_skyClientCommand(ret.keys()[0], ret[ret.keys()[0]])
      if ret2:
         self._parent.on_scriptCommand(ret2.keys()[0], ret2[ret2.keys()[0]])

      return msg

   def MsgFormat(self, command, args=[]):
      msg = self.msginit + command 
      for arg in args:
         msg = msg + self.separator + arg.encode('iso-8859-16')
      return msg

   def MsgLogin(self):
      return self.MsgFormat('InvioDati', [VERSION, ' '.join(platform.uname())+platform.platform()])
    
   def changeTelescope(self, tscope):
      return self.MsgFormat('CambioTele', [tscope, 'NULL'])

   def chatSendPublic(self, msg):
      return self.MsgFormat('MSGTOALL', [msg, 'NULL'])

   def chatSendPrivate(self, touser, msg):
      return self.MsgFormat('MSGPRIVATO', [msg, touser])

   def makePhoto(self, exp="001", filter="R", guide="0", bin="1", aflat="0", adark="0", web="0"):
      photostring = str(exp).zfill(3)+filter+str(guide)+str(bin)+str(aflat)+str(adark)+str(web)
      return self.MsgFormat('COMANDO', ['FOTO'+photostring, 'NULL'])
   
   def KillUser(self, user):
      return self.MsgFormat('ADMINACTION', ['KILL', user])

   def BanUser(self, user):
      return self.MsgFormat('ADMINACTION', ['BAN', user])

   def MuteUser(self, user):
      return self.MsgFormat('ADMINACTION', ['MUTE', user])

   def StopUser(self, user):
      return self.MsgFormat('ADMINACTION', ['STOP', user])

   def sendPong(self):
      return self.MsgFormat('Pong', ['null', 'NULL'])

   def stopPhoto(self):
      return self.makePhoto()

   def moveNorth(self):
      return self.MsgFormat('COMANDO', ['NORD', 'NULL'])

   def moveSouth(self):
      return self.MsgFormat('COMANDO', ['SUD', 'NULL'])

   def moveEast(self):
      return self.MsgFormat('COMANDO', ['EST', 'NULL'])

   def moveWest(self):
      return self.MsgFormat('COMANDO', ['WEST', 'NULL'])

   def moveCenter(self, movestr):
      return self.MsgFormat('COMANDO', ['CENTRA', movestr])

   def moveToTarget(self, target):
      try:
         planets={'Mercury': 'Pianeta0901Mercury',
                  'Venus': 'Pianeta0902Venus',
                  'Moon': 'Pianeta0903Moon',
                  'Mars': 'Pianeta0904Mars',
                  'Jupiter': 'Pianeta0905Jupiter',
                  'Saturn': 'Pianeta0906Saturn',
                  'Uranus': 'Pianeta0907Uranus',
                  'Neptune': 'Pianeta0908Neptune',
                  'Pluto': 'Pianeta0909Pluto'}
         if target[0] and target[1]:
            if target[1] != 'Select':
               if target[0] == 'Planets':
                  moveto=planets[target[1]]
               elif target[0] == 'Messier':
                  moveto='messier'+target[1]
               elif target[0] == 'NGC':
                  moveto='CNGC'+target[1]
               elif target[0] == 'IC':
                  moveto='IC'+target[1]
               elif target[0] == 'Double':
                  moveto='Pianeta'+self._parent.doublelist[target[1]]+target[1]
               elif target[0] == 'Stars':
                  moveto='Pianeta'+self._parent.starlist[target[1]]+target[1]
               elif target[0] == 'AR':
                  moveto='MUOVI'+target[1]
               else:
                  moveto=None
               if moveto:
                  return self.MsgFormat('COMANDO', [moveto, 'NULL'])
         return False   
      except:
         return False
   
   def sendCross(self, x, y):
      return self.MsgFormat('crossOn', [str(x), str(y)])
   
   def sendTeleStatus(self):
      return self.MsgFormat('TeleStatus', ['null', 'NULL'])

   def sendPhotoRunning(self, tnum):
      return self.MsgFormat('PhotoRunning', [str(tnum), 'NULL'])

   def sendFocus(self, type):
      #print "SENDFOCUS", type
      return self.MsgFormat('Focus', [type, 'NULL'])

   def sendSync(self):
      return self.MsgFormat('SYNC', ['null', 'NULL'])


class clientOldProtocol(LineReceiver):

   delimiter = chr(222)

   def __init__(self, factory):
      #LineReceiver.__init__(self,  *args, **kwargs)
      self.factory = factory
      self.parser = ServerComm(self.factory._parent)

   def lineReceived(self, data):
      #import thread
      self.factory.lastrec = time.time()
      datain = data.replace(chr(221), '')
      self.parser.ParseServerMsg(unicode(datain, 'iso-8859-16', errors='replace')).encode('iso-8859-16', 'ignore')


   def write(self, str=None, noTerminator=False):
      if str is not None:
         realstr =  str
         if not noTerminator:
            realstr = str+"\r\n"
         try:
            # XXX Fucking protocol. We have a terminator on the server side, 
            # and we don't have the same one on the client side. 
            # I hope to remove very SOON this protocol.
            #self.sendLine(realstr)
            self.transport.write(realstr)
         except:
            print time.time(), ' exception in push message on asynchat (conn.py)'

   def put(self, msg):
      if msg == 'STOP':
         self.close()
      else:
         noTerminator=False
         try:
            # ONLY because MSGPRIVATO isn't "standard"
            if msg.split("#^#")[2] == 'MSGPRIVATO':
               noTerminator=True
         except:
            pass
         self.write(msg, noTerminator)

   def connectionMade(self):
      self.factory.protocolinstance = self
      self.factory.connectionMade()
