# This file serves as an entry point, and contains most of the API for the linedb functions.
# The code for commands in kernel/python/linedb/pro (or wherever else) should use
# the functions defined here rather than directly the ones in db.py, jpl.py etc.

import os
import sqlite3
from linedb import db
import linedb.jpl as jplmod
from linedb import vamdc
from linedb import cdms
from linedb import slap
import numpy
import pysic
from linedb.list import llist

origins = db.origins
sortCrit = ["frequency", "energy", "aij"]

# TODO(mpl): it would be nice not to preload all those. I need to bench
# how much mem is wasted that way.
voparis = slap.Slap(url = "http://linelists.obspm.fr/transitions.php?base=cdms&",
             cache_file = "~/.gag/scratch/voparis.db", protocol = "slap",
             online = True, name = "voparis")

camvamdc = slap.Slap(url = "http://casx019-zone1.ast.cam.ac.uk/vamdc-slap/slap?",
            cache_file = "~/.gag/scratch/cam-vamdc.db", protocol = "slap",
            online = True, name = "cam-vamdc")

splatalogue = slap.Slap(url = "http://find.nrao.edu/splata-slap/slap?",
                cache_file = "~/.gag/scratch/splatalogue.db", protocol = "slap",
                online = True, name = "splatalogue")

cdms = cdms.default

jpl = jplmod.default

cdmsvamdc = vamdc.Vamdc(
              url = "http://cdms.ph1.uni-koeln.de/cdms/tap/sync?",
              cache_file = "~/.gag/scratch/cdmsvamdc.db",
              protocol = "cdms_post",
              online = True,
              name = "cdms-vamdc")

dbin = None
dbout = None
linesOut = []
lineIdx = -1  # 0 = first elements, -1 = before first element
# N.B: as soon as they're declared as globals in one of the funcs they're not None anymore. wtf.

def use(db_name, mode, online=True, overwrite=False, astro=False):
   """
   Select a database

   Arguments:
   db_name  -- a list of databases
   online   -- make online searches (default True)
   mode -- in, out or both

   """
   global dbin
   global dbout

   # Databases with more or less correct support in LineDB:
   #onlineDbs = {"voparis": voparis, "cam-vamdc": camvamdc, "splatalogue": splatalogue,
                #"cdms": cdms, "cdms-vamdc": cdmsvamdc, "jpl": jpl}
   # Long term support to all users:
   onlineDbs = {"cdms": cdms, "jpl": jpl}

   alldb = []
   overwriteOrNew = overwrite
   for d in db_name:
      try:
         # Try online databases first
         mydb = onlineDbs[d.lower()]  # Case-insensitive
         if not online:
            # trick to just escape to the exception block, using the cache file as d
            d = mydb.cache_file
            raise KeyError("offline mode -> local db")
         # TODO(mpl): get rid of setonline if possible
         mydb.setonline(online)
         alldb.append(mydb)
      except KeyError:
         # Must be an offline database (local file)
         d = pysic.parsefile(d)
         if not os.path.isfile(d):
            if mode in ["in", "both"]:
               raise ValueError("Unknown database name or file: {0}".format(d))
            overwriteOrNew = True
         if os.path.isabs(d):
            url = d
         else:
            url = os.path.abspath(d)
         if astro:  # A local Astro catalog
            if mode == "in":
               raise Exception("ASTRO catalogs can not be used as input")
            mydb = db.AstroCatalog(url=url, name=d, overwrite=overwriteOrNew)
         elif db.isDbFile(url) or overwriteOrNew:  # A local SQlite database
            mydb = db.Local(url=url, name=d, overwrite=overwriteOrNew)
         else:
            if mode == "in":
               dir = os.path.dirname(d)
               partfuncfilejson = os.path.join(dir, "partfunc.json")
               if not os.path.isfile(partfuncfilejson):
                  partfuncfilecat = os.path.join(dir, "partfunc.cat")
                  if not os.path.isfile(partfuncfilecat):
                     raise Exception("partitions file not found ({0} or {1})".format(partfuncfilejson, partfuncfilecat))
               mydb = jplmod.Catfile(url = url,
                  cache_file = "", protocol = "catfile",
                  online = False, name = d)
            else:
               raise Exception("{0} is not a valid local sqlite db".format(url))
         alldb.append(mydb)

   databases = db.mlinedb(alldb)
   if mode == "in":
      dbin = databases
   elif mode == "out":
      dbout = databases
   else:
      dbin = databases
      dbout = databases


def lget(where):
   """
   Get a line from the line index

   """

   global linesOut
   global lineIdx

   if where == "f":
      lineIdx = 0;
   elif where == "l":
      lineIdx = len(linesOut) - 1
   elif where == "n":
      if lineIdx == len(linesOut) - 1:
         raise IndexError("End of index encountered")
      else:
         lineIdx += 1
   elif where == "p":
      if lineIdx == 0:
         raise IndexError("Beginning of index encountered")
      else:
         lineIdx -= 1
   else:
      try:
         lineIdx = int(where) - 1 # start at 0!
      except:
         raise IndexError("Incorrect value")

   # Get the line frequency from the line index
   return linesOut[lineIdx]

def equivPartition():
   global linesOut
   species = []
   partitions = {}
   for i in range(len(linesOut)):
      l = linesOut[i]
      found = False
      for spec in species:
         if l.species == spec:
            partitions[spec].append(l)
            found = True
            break
      if not found:
         species.append(l.species)
         partitions[l.species] = [l]

   return partitions


### Make those elements visible (public) to external callers
### Declare them last because of circular dependencies (so that
### the elements needed in select.py are all declared above)
from linedb.select import select,select_command
### All done
