#!/usr/bin/python -i

backgrounds=[]

import sys
import globals
from globals import *

SERVER = False
CLIENT = True
globals.SERVER = SERVER
globals.CLIENT = CLIENT
filef = logging.Formatter("%(asctime)s: %(name)s-%(levelname)s (%(threadName)-10s) %(message)s")
conf = logging.Formatter("%(name)s-%(levelname)s (%(threadName)-10s) %(message)s")
try:
  sfh = logging.FileHandler(LOGFILES['Client'])
except IOError:    #Can't open a logfile for writing, probably the wrong user
  sfh = logging.NullHandler()

sfh.setLevel(LOGLEVELS['Server']['File'])
sfh.setFormatter(filef)
# create console handler with a different log level, and without timestamps
#conh = logging.StreamHandler(sys.stdout)
#conh.setLevel(LOGLEVELS['Server']['Console'])
#conh.setFormatter(conf)
# create global logger object
logger = logging.getLogger("Prosp")
logger.setLevel(MLOGLEVEL)
# add the handlers to the logger
logger.addHandler(sfh)
#logger.addHandler(conh)
#Make it the default logger for everything else in this process that imports 'globals'
globals.logger = logger

import Andor
import AnCommands

try:
  import readline
except ImportError:
  logger.error("Module readline not available.")
else:
  import rlcompleter
  readline.parse_and_bind("tab: complete")

import sys
import time       #for the 'sleep' function
import types
import threading
import improc
from improc import reduce
import planet
from planet import *
import telescope
from telescope import *
from snlists import *
import weather
import pipeline
import service
import snsearch
import scheduler
import prospserver
import chiller

import focuser
from focuser import Goto,getPos,Home,Tzero,Tcorrect

import focus
from focus import *

backgrounds.append(telescope._background)
backgrounds.append(weather._background)
if CHILLER:
  backgrounds.append(chiller._background)

import utils
from utils import *
import ephemint
from ephemint import *


def help(func):
  "Usage: help(function) to find out information about that function"
  if type(func)==type(''):
    print "     "+getattr(__builtins__.globals()[func],'func_doc')
  else:
    print "     "+func.func_doc


def _background():
  "Call each of the registered background functions every 6 seconds"
  while 1:
    try:
      if status.MonitorActive:
        if status.weather.clear and isdark() and (not telescope.Active.isSet()):
          logger.info("Conditions clear, resuming observing.")
          telescope.unpause()
          status.lastact=time.time()   #Reset the last image time so we don't
                                       #trip the inactivity timeout right away
        if (not status.weather.clear) and telescope.Active.isSet():
          logger.warning("Conditions Cloudy, pausing observing.")
          telescope.pause()
        if (not ephemint.isdark()) and telescope.Active.isSet():
          logger.warning("End of the night, pausing forever. To resume "+
                 "and open dome, type 'teljoy.unpause()'")
          telescope.pause()
          status.MonitorActive = False
        try:
          Alt=float(status.TJ.Alt)
          if status.TJ.RawHourAngle>0:
            Alt=90        #Don't worry about low altitudes east of the zenith
        except:
          Alt=0           #If there's an error getting Alt, don't risk it, close up
        if ( ((not status.imaging) and (time.time()-status.lastact > 3600)) or
             ((not status.imaging) and (time.time()-status.lastact > 300) and (Alt<20)) or
             ((not status.imaging) and (Alt<15)) or
             (Alt<12) ) and telescope.Active.isSet():
          logger.warning("System Inactive or below Alt limits, pausing forever. To "+
                 "resume and open dome, type 'teljoy.unpause()'")
          telescope.pause()
          status.MonitorActive = False

      status.isdark = ephemint.isdark()
      status.update()    #Get new data from Pyro server, and save pickled status object.

      for f in backgrounds:    #Call all the registered background functions
        try:
          f()
        except:
          logger.exception("Exception in background function: %s\n" % f)
          logger.info("Continuing...")

    except:
      logger.exception("Exception in main Prosp background thread")
      logger.info("Continuing...")

    time.sleep(6)            #Wait 6 seconds, then repeat


class Prompt:
  """Class to assign to sys.ps1, str() method is called every time a prompt is
     printed. Used to make sure that the background thread is still alive.
  """
  def __str__(self):
    global BGThread
    if GotCamera:
      if not BGThread.isAlive():
        BGThread=threading.Thread(group=None,
                                  target=_background)
        BGThread.setDaemon(1)
        BGThread.start()
        logger.error("Dead background thread restarted.")
    return ">>>"



def monitor(arg=None, close=None, open=None, delay=None):
  """Usage: monitor('ON') or monitor('OFF')
  Turns weather monitoring on or off. Uses default cloud parameters, or the
  values previously set if the command has been used previously in a session.
    or:
  monitor('ON', close=-28, open=None, delay=1800)
  Use monitor() with no arguments to get the current weather status.

  If the 'close', 'open' and 'delay' parameters are given, uses these for
  SkyCloseTemp, SkyOpenTemp and WeatherOpenDelay respectively.
  These parameters are:
  SkyCloseTemp:  When the current sky temp is above this value, the dome 
                    closes and the system pauses.
  SkyOpenTemp:   If the system is paused, the sky temp needs to be less
                    than this value for it to be 'clear'. If this is not given,
                    it defaults to the same as the close value.
  WeatherOpenDelay: If the system is paused, the weather needs to be 'clear'
                    (see above) for this many seconds before the system is
                    un-paused.
  """
  if open is None:
    open = close
  if type(arg)==types.StringType:
    arg = string.upper(arg)
  if arg == 'OFF':
    print "Monitoring OFF."
    status.MonitorActive = False

    if type(close)==types.FloatType or type(close)==types.IntType:
      status.weather.SkyCloseTemp = float(close)
    if type(open)==types.FloatType or type(open)==types.IntType:
      status.weather.SkyOpenTemp = float(open)
    if type(delay)==types.FloatType or type(delay)==types.IntType:
      status.weather.WeatherOpenDelay = int(delay)

#Don't open up dome again if we switch off monitoring after it's paused due to bad weather
#    if not teljoy.Active.isSet():
#      teljoy.unpause()
  elif arg == 'ON':
    while (not ephemint.isdark()):
      print 'waiting for it to get dark:'
      time.sleep(90)
    status.isdark = ephemint.isdark()
    status.weather.__init__()
    status.lastact = time.time()   #In case it's been a while since an image
    if type(close)==types.FloatType or type(close)==types.IntType:
      status.weather.SkyCloseTemp = float(close)
    if type(open)==types.FloatType or type(open)==types.IntType:
      status.weather.SkyOpenTemp = float(open)
    if type(delay)==types.FloatType or type(delay)==types.IntType:
      status.weather.WeatherOpenDelay = int(delay)
    if not status.isdark:
      print "It's not dark yet, monitoring mode would pause immediately."
      print "Monitor mode aborted."
      return 0
    if not status.weather.clear:
      print "Monitor mode aborted:\n",
      if status.weathererror:
        print status.weathererror
      else:
        print "Weather unstable"
      status.weather.display()
      return 0

    status.MonitorActive = True
    print "Monitoring ON, 'clear' delay reset to force immediate unpausing\n"
    status.weather.display()
  else:   #Arg not on or off
    print "type 'help(monitor)' for usage information.\nStatus:"
    status.weather.display()
    
    


sys.ps1=Prompt()

AnCommands.init()        #Call the init() function in the library to open
from AnCommands import *

status = AnCommands.camera.status  #Define a status variable using the new class
status.TJ = telescope.status

weather.Init()
status.weather = weather.status
status.MonitorActive = False
status.isdark = ephemint.isdark()
status.lastact = time.time()
utils.status = status       #And the utility commands module
prospserver.status = status

sys.path = sys.path + ['.']   #Allow user-written modules in current dir to load

status.chiller = chiller.status
status.focuser = focuser.status

if status.initialized:
  GotCamera = True
  logger.info("Contact established with Andor camera server.")
  if CHILLER:
    chiller.init()
  if FOCUSER:
    focuser.init()
else:
  GotCamera = False
  logger.error("Camera init failed.")
  logger.error("Can't connect to the Andor server program to control the camera.")
  print "Continuing without access to the camera hardware."


if GotCamera:
  BGThread=threading.Thread(group=None,
                     target=_background)
  BGThread.setDaemon(True)
  BGThread.start()

#Move this up so it's only started if we're actually connected to a camera.
prospserver.InitServer()

try:
  motd = open('/tmp/andor.motd','r')
  print "\nMessage of the Day:\n"
  print motd.read()+"\n\n"
  motd.close()
except:
  pass

