#=============================================================================
#
#  Copyright (c) Kitware, Inc.
#  All rights reserved.
#  See LICENSE.txt for details.
#
#  This software is distributed WITHOUT ANY WARRANTY; without even
#  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#  PURPOSE.  See the above copyright notice for more information.
#
#=============================================================================

def __bootstrap_smtk__():
  import sys, os

  shiboken_lib = "@SHIBOKEN_LIBRARY@"
  shiboken_path = os.path.dirname(shiboken_lib)
  smtk_path = "@LIBRARY_OUTPUT_PATH@"

  extra_paths = [shiboken_path, smtk_path]
  for (path, dirs, files) in os.walk(shiboken_path, topdown=False):
    #walk shiboken path and find the python/site-packages sub folders
    #add this to sys path
    x = [os.path.join(path,dir) for dir in dirs if "site-packages" in dir]
    if len(x) > 0:
      extra_paths = extra_paths + x
  sys.path = sys.path + extra_paths

if '@smtk_find_shiboken@':
  __bootstrap_smtk__()

def __import_shared_ptrs__():
  import re
  extract_name = re.compile("\W+")
  def __make_clean_name(name,obj):

    #known classes with the same name between the modules
    known_clashes = ("Manager", "Item")

    #split the name so we will have
    #[shared_ptr, smtk, model/atribute, name]
    split_name = [i for i in re.split(extract_name, name)]

    #assign the name
    new_name = split_name[3]
    #if the name is a known clashable name, extract the namespace
    #and make it a title
    if(new_name in known_clashes):
      new_name = split_name[2].title()+new_name

    #assign ptr to the end of the name
    return new_name+"Ptr"

  for i in _temp.__dict__:
    #I can't seem to find the type Shiboken.ObjectType, so we will hope
    #the inverse allways works
    if not isinstance(_temp.__dict__[i],(str)):
      try:
        name = __make_clean_name(i,_temp.__dict__[i])
        #now we are also going to
        globals()[name]  = _temp.__dict__[i]
      except:
        pass

#import the modules information we need.
#We are using _import__ since shiboken doesn't create proper python modules
#We can't just import smtkCorePython.smtk.model as model, so instead
#we have to use _import__ so that we get a nice interface.

import shiboken
_temp = __import__('smtkCorePython', globals(), locals(), [], -1)
__import_shared_ptrs__()
common = _temp.smtk.common
attribute = _temp.smtk.attribute
model = _temp.smtk.model
mesh = _temp.smtk.mesh
simulation = _temp.smtk.simulation
io = _temp.smtk.io

try:
  _tempext = __import__('smtkIOVTKPython', globals(), locals(), [], -1)
  __import_shared_ptrs__()
  extension = _tempext
except:
  pass

# Try loading optional extensions.
# Do not complain if they are not present.
try:
  import smtkRemusExtPy
except:
  pass

# Try importing bridge session modules. They may not be built, so don't complain on failure.
try:
  from collections import namedtuple
  btuple = []
  failed = []
  _tempmain = _temp
  try:
    _tempcgm = __import__('smtkCGMSessionPython', globals(), locals(), [], -1)
    _temp = _tempcgm
    __import_shared_ptrs__()
    btuple.append(('cgm', _tempcgm.cgm))
  except:
    failed += ['cgm']
  finally:
    _temp = _tempmain

  try:
    _tempexo = __import__('smtkExodusSessionPython', globals(), locals(), [], -1)
    _temp = _tempexo
    __import_shared_ptrs__()
    btuple.append(('exodus', _tempexo.exodus))
  except:
    failed += ['exodus']
  finally:
    _temp = _tempmain

  try:
    _tempdis = __import__('smtkDiscreteSessionPython', globals(), locals(), [], -1)
    _temp = _tempdis
    __import_shared_ptrs__()
    btuple.append(('discrete', _tempdis.discrete))
  except:
    failed += ['discrete']
  finally:
    _temp = _tempmain

  try:
    _tempdis = __import__('smtkPolygonSessionPython', globals(), locals(), [], -1)
    _temp = _tempdis
    __import_shared_ptrs__()
    btuple.append(('polygon', _tempdis.polygon))
  except:
    failed += ['polygon']
  finally:
    _temp = _tempmain

  try:
    _tempremote = __import__('smtkRemoteSessionPython', globals(), locals(), [], -1)
    _temp = _tempremote
    __import_shared_ptrs__()
    btuple.append(('remote', _tempremote.remote))
  except:
    failed += ['remote']
  finally:
    _temp = _tempmain

  try:
    _tempmesh = __import__('smtkMeshSessionPython', globals(), locals(), [], -1)
    _temp = _tempmesh
    __import_shared_ptrs__()
    btuple.append(('mesh', _tempmesh.mesh))
  except:
    failed += ['mesh']
  finally:
    _temp = _tempmain

  if len(btuple) > 0:
    bridgeModule = namedtuple('bridgeModule', ' '.join([x for x,y in btuple]))
    bridge = bridgeModule(*[y for x,y in btuple])
  else:
    bridge = None
except:
  bridge = None


attribute.type_dict = { attribute.Item.ATTRIBUTE_REF: (attribute.RefItem, attribute.RefItemDefinition),
                        attribute.Item.DOUBLE: (attribute.DoubleItem, attribute.DoubleItemDefinition),
                        attribute.Item.GROUP: (attribute.GroupItem, attribute.GroupItemDefinition),
                        attribute.Item.INT: (attribute.IntItem, attribute.IntItemDefinition),
                        attribute.Item.STRING: (attribute.StringItem, attribute.StringItemDefinition),
                        attribute.Item.VOID: (attribute.VoidItem, attribute.VoidItemDefinition),
                        attribute.Item.FILE: (attribute.FileItem, attribute.FileItemDefinition),
                        attribute.Item.DIRECTORY: (attribute.DirectoryItem, attribute.DirectoryItemDefinition),
                        attribute.Item.COLOR: (None, None),
                        attribute.Item.MODEL_ENTITY: (attribute.ModelEntityItem, attribute.ModelEntityItemDefinition),
                        attribute.Item.MESH_ENTITY: (attribute.MeshItem, attribute.MeshItemDefinition),
                        attribute.Item.MESH_SELECTION: (attribute.MeshSelectionItem, attribute.MeshSelectionItemDefinition)
                      }

@staticmethod
def __to_concrete__(item):
  '''
    Returns concrete (leaf) object for input, which is smtk.attribute.Item
  '''
  def fun(i):
    concrete_item = None
    for item_type,klass in attribute.type_dict.items():
      if i.type() == item_type:
        try:
          concrete_item = klass[0].CastTo(i)
          break
        except TypeError:
          concrete_item = klass[1].CastTo(i)
          break
    if concrete_item is None:
      print 'WARNING - unsupported type %s, item %s' % \
        (i.type(), i.name())
    return concrete_item
  if isinstance(item, list):
      return [ fun(x) for x in item ]
  elif isinstance(item, tuple):
      return tuple([ fun(x) for x in item ])
  elif isinstance(item, set):
      return set([fun(x) for x in item])
  return fun(item)

attribute.to_concrete = __to_concrete__
del __to_concrete__

def addItemDefinition( self, data_type, name):
  def_ = data_type.New(name)
  if def_ is None:
    print "could not create"
    return None
  idef = data_type.ToItemDefinition(def_)
  if idef is None:
    print "could not convert"
    return None
  if not self.addItemDefinition(idef):
    print "could not add"
    return None
  return def_

DefinitionPtr.addItemDefinitionStr = addItemDefinition
DirectoryItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
DoubleItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
FileItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
GroupItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
IntItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
ItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
RefItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
StringItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
MeshSelectionItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
ModelEntityItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
ValueItemDefinitionPtr.addItemDefinitionStr = addItemDefinition
VoidItemDefinitionPtr.addItemDefinitionStr = addItemDefinition

import inspect

def _Debug( self, message ):
  cs = inspect.stack()
  at = 1
  if len(cs) < 1:
    at = 0
  self.addRecord(io.Logger.DEBUG, str(message), cs[at][1],  cs[at][2])

def _Error( self, message ):
  cs = inspect.stack()
  at = 1
  if len(cs) < 1:
    at = 0
  self.addRecord(io.Logger.ERROR, str(message), cs[at][1],  cs[at][2])

def _Warn( self, message ):
  cs = inspect.stack()
  at = 1
  if len(cs) < 1:
    at = 0
  self.addRecord(io.Logger.WARNING, str(message), cs[at][1],  cs[at][2])

io.Logger.addDebug = _Debug
io.Logger.addWarning = _Warn
io.Logger.addError = _Error

del _Debug
del _Warn
del _Error


def to_concrete(instance):
  '''General type converter for smtk objects
  '''
  # Use current smtk.attribute.to_concrete() for its types
  if instance.__class__.__module__.endswith('smtk.attribute') or \
    str(instance.__class__).find('smtk::attribute::') > 0:
      return attribute.to_concrete(instance)
  # (else)
  print 'no converter available for class %s, cannot convert' % \
      str(instance.__class__)
  print 'module', instance.__class__.__module__
  print 'class', instance.__class__
  return None

def wrappingProtocol():
  return 'shiboken'

import datetime
def DateTimeZonePair_to_python(self, utc=False):
  '''Returns python datetime instance, or None if not set.

  This is a bare datetime instance with NO tzinfo.
  It returns local time by default.
  If the utc arugment is set, it will internally convert
    to UTC and return that as the contents of the datetime instance.
  If the SMTK DateTime is not set, returns None.
  If utc is True but TimeZone not set, returns None.
  '''
  smtk_dt = self.dateTime()
  smtk_tz = self.timeZone()

  if not smtk_dt.isSet():
    return None

  if utc and not smtk_tz.isSet():
    return None

  # (else)
  if (utc):
    smtk_tz = common.TimeZone()  # unset TimeZone instance
  smtk_comps = smtk_dt.components(smtk_tz)

  python_comps = list(smtk_comps)
  python_comps[-1] *= 1000  # convert smtk/msec to python/usec
  dt = datetime.datetime(*python_comps)
  return dt

common.DateTimeZonePair.to_python_datetime = DateTimeZonePair_to_python
