
import os

from org.gvsig.app import ApplicationLocator
from org.gvsig.fmap.dal.feature import FeatureType
from java.util.prefs import Preferences
from org.gvsig.fmap.mapcontext import MapContextLocator
from java.awt import Color
from java.io import File
from java.lang import Throwable, RuntimeException
from project import currentView, currentProject

def createFeatureType(schema = None):
  """Returns attributes definition. If Schema is recived then makes a copy and
  returns editable instance. Otherwise returns empty Schema.
  :param schema: Schema to make a copy
  :type schema: Schema
  """
  if isinstance(schema, FeatureType):
    try:
      s = schema.getCopy().getEditable()
      return s
    except:
      pass

  application = ApplicationLocator.getManager()
  datamanager =  application.getDataManager()
  return datamanager.createFeatureType()

createSchema = createFeatureType

def createLayer(schema, servertype, layertype=None, **parameters):
  """
  Returns new layer
  :param schema: layer data definition
  :type schema: Schema
  :param servertype:
  :type servertype: string
  :return: new layer
  :rtype: Layer
  :raise: RuntimeException
  """
  if layertype == None:
    layertype = servertype
    servertype = "FilesystemExplorer"

  if layertype == "Shape" :
    if schema.get("GEOMETRY",None) == None:
      raise RuntimeException("Shape need a field named GEOMETRY in the schema")

  if parameters["geometryType"] == None:
    raise RuntimeException("Invalid geometry type for new layer")

  try:
    application = ApplicationLocator.getManager()
    datamanager =  application.getDataManager()

    mapcontextmanager = application.getMapContextManager()

    server_parameters = datamanager.createServerExplorerParameters(servertype)
    copyToDynObject(parameters, server_parameters)

    server = datamanager.openServerExplorer(servertype, server_parameters)

    store_parameters = server.getAddParameters(layertype)
    copyToDynObject(parameters, store_parameters)
    store_parameters.setDefaultFeatureType(schema)

    server.add(layertype, store_parameters, True)

    store = datamanager.openStore(layertype, store_parameters)

    layer = mapcontextmanager.createLayer(store.getName(), store)

    return layer

  except Throwable, ex:
    raise RuntimeException("Can't create layer, "+ str(ex))

def loadShapeFile(shpFile, **parameters):
    """
    Add existing shape file to the view. Returns Layer shape file
    :param shpFile: absolute file path
    :type: shpFile: string
    :param CRS: projection code
    :type CRS: string
    :return: the shape
    :type return: Layer
    """
    if parameters.get("CRS",None)==None:
      parameters["CRS"]="EPSG:4326"
    parameters["shpFile"]=shpFile
    layer = loadLayer('Shape', **parameters)
    viewName = parameters.get("gvViewName",None)
    if viewName == None:
      view = currentView()
    else:
      project = currentProject()
      view = project.getView(viewName)
      if view == None:
	raise RuntimeException("Can't get view with name '"+viewName+"', "+ str(ex))
    view.addLayer(layer)
    layer.setActive(True)
    return layer

def loadRasterFile(filename, **parameters):
    parameters["uri"]= File(filename).toURI()
    ext = os.path.splitext(filename)
    #if ext[1].lower() == ".jp2" or ext[1].lower()=="ecw":
    #  layer = loadLayer("Ermapper Store", **parameters)
    #else:
    #  layer = loadLayer('Gdal Store', **parameters)
    layer = loadLayer('Gdal Store', **parameters)
    viewName = parameters.get("gvViewName",None)
    if viewName == None:
      view = currentView()
    else:
      project = currentProject()
      view = project.getView(viewName)
      if view == None:
	raise RuntimeException("Can't get view with name '"+viewName+"', "+ str(ex))
    view.addLayer(layer)
    layer.setActive(True)
    return layer

def loadLayer(layerType, **parameters):
    try:
        application = ApplicationLocator.getManager()
        datamanager =  application.getDataManager()
        mapcontextmanager = application.getMapContextManager()
        store_parameters = datamanager.createStoreParameters(layerType)
        copyToDynObject(parameters, store_parameters)
        store = datamanager.openStore(layerType, store_parameters)
        layerName = parameters.get("gvLayerName", store.getName())
        layer = mapcontextmanager.createLayer(layerName, store)
    except Throwable, ex:
        raise RuntimeException("Can't load layer, "+ str(ex))

    return layer

def createShape(definition, filename, geometryType=None, CRS="CRS:84"):
  """
  Return new shape layer
  :param definition: layer data definition
  :type definition: Schema
  :param filename: absolute path for shape files.
  :type filename: string
  :param geometryType: geometry type for shape
  :type geometryType: string
  :return: new shape layer
  :rtype: Layer
  """
  geomattr = definition.getDefaultGeometryAttribute()
  if geomattr == None:
    raise RuntimeException("Can't create a shp without geometry attribute")
  if geometryType == None :
    geometryType = geomattr.getGeomType().getType()
  else:
    if geometryType != geomattr.getGeomType().getType():
      raise RuntimeException("Can't create a shp, geoemtry mismatch.")

  return createLayer(
    definition,
    "FilesystemExplorer",
    "Shape",
    shpFile=filename,
    CRS=CRS,
    geometryType = geometryType
  )

def createTable(schema, servertype, tableType=None, **parameters):
  """Creates a new Table document"""
  if tableType == None:
    tableType = servertype
    servertype = "FilesystemExplorer"

  try:
    application = ApplicationLocator.getManager()
    datamanager =  application.getDataManager()

    server_parameters = datamanager.createServerExplorerParameters(servertype)
    copyToDynObject(parameters, server_parameters)

    server = datamanager.openServerExplorer(servertype, server_parameters)

    store_parameters = server.getAddParameters(tableType)
    copyToDynObject(parameters, store_parameters)
    store_parameters.setDefaultFeatureType(schema())

    server.add(tableType, store_parameters, True)

    store = datamanager.openStore(tableType, store_parameters)

    return store

  except Throwable, ex:
    raise RuntimeException("Can't create table, "+ str(ex))

def createDBF(definition, DbfFile, CRS="CRS:84"):
  """
  Creates a new dbf document
  :param definition: layer data definition
  :type definition: Schema
  :param DbfFile: absolute path for shape files.
  :type DbfFile: string
  :return: new dbf
  :rtype: Table
  """
  return createTable(
    definition,
    "FilesystemExplorer",
    "DBF",
    DbfFile=DbfFile,
    CRS=CRS,
  )


#=====================#
# Simbology Functions #
#=====================#
COLORS = {
    'black': Color.black,
    'blue': Color.blue,
    'cyan': Color.cyan,
    'darkGray': Color.darkGray,
    'gray': Color.gray,
    'green': Color.green,
    'lightGray': Color.lightGray,
    'magenta': Color.magenta,
    'orange': Color.orange,
    'pink': Color.pink,
    'red': Color.red,
    'white': Color.white,
    'yellow': Color.yellow,
}

def simplePointSymbol(color=None):
  """
  Returns simple point symbol using parameter color. If no color
  use a ramdom color
  :param color: String color name or Java awt Color
  :return: gvSIG point symbol
  """
  if isinstance(color, str) and COLORS.has_key(color.lower()):
    color = COLORS.get(color)

  if not isinstance(color, Color):
      color = getDefaultColor()

  return MapContextLocator.getSymbolManager().createSymbol(
        Geometry.TYPES.POINT, color)

def simpleLineSymbol(color=None):
  """
  Returns simple line symbol using parameter color. If no color use a
  ramdom color
  :param color: String color name or Java awt Color
  :return: gvSIG line symbol

  """
  if isinstance(color, str) and COLORS.has_key(color.lower()):
    color = COLORS.get(color)

  if not isinstance(color, Color):
      color = getDefaultColor()

  return MapContextLocator.getSymbolManager().createSymbol(
        Geometry.TYPES.CURVE, color)

def simplePolygonSymbol(color = None):
  """
  Returns simple polygon symbol using parameter color. If no color
  use a ramdom color.
  :param color: String color name or Java awt Color
  :return: gvSIG polygon symbol
  """
  if isinstance(color, str) and COLORS.has_key(color.lower()):
    color = COLORS.get(color)

  if not isinstance(color, Color):
      color = getDefaultColor()

  return MapContextLocator.getSymbolManager().createSymbol(
        Geometry.TYPES.SURFACE, color)


#=========================================#
# gvSIG Application Preferences Functions #
#=========================================#

def getDataFolder():
  """
  Returns gvSIG data folder. This folder is defined in application
  preferences. If is not defined returns None.
  """
  return Preferences.userRoot().node("gvsig.foldering").get('DataFolder', None)

def getProjectsFolder():
  """
  Returns gvSIG projects folder. This folder is defined in application
  preferences. If is not defined returns None.
  """
  return Preferences.userRoot().node("gvsig.foldering").get(
        'ProjectsFolder', None)

def getColorFromRGB(r, g, b, a=None):
  """
  Returns an sRGB color with the specified red, green, blue, and alpha
  (optional) values in the range (0 - 255).
  """
  if a:
    color = Color(r, g, b, a)
  else:
    color = Color(r, g, b)

  return color

def getDefaultColor(c = None):
  """Returns gvsig default symbol fill color or ramdom color"""
  if MapContextLocator.getSymbolManager().isDefaultSymbolFillColorAleatory():
    color = Color(random.randint(0-255),
                random.randint(0-255),
                random.randint(0-255)
            )
  else:
    sp = MapContextLocator.getSymbolManager().getSymbolPreferences()
    color = sp.getDefaultSymbolFillColor()

  return color

#================#
# OTHER          #
#================#

def getCRS(crs):
  """Returns Projection from string code (i.e. CRS:84) if exist or None if
  not.
  """
  try:
    return CRSFactory.getCRS(crs)
  except:
    return None

def copyToDynObject(values, target):
  definition = target.getDynClass();
  fields = definition.getDynFields();
  for field in fields:
    name = field.getName()
    keys = values.keys()
    for k in keys:
      if k.lower() == name.lower():
        target.setDynValue(name, values[name])
        break
# ====================================
#

"""
def cloneShape(layer, target=None, expresion = None, sortby="", asc=True):
  if target==None:
    #  una capa temporal en el temp de andami
    #...
  else:
    targetfile = File(target)
    if targetfile.isAbsolute():
      #La guardamos ahi mismo
    else:
     # Al temp de andami con ese nombre.

  # Crear la nueva capa

  return newLayer
"""