
import com.jeta.forms.components.panel.FormPanel

import java.lang.Runnable
import java.io.FileInputStream
import java.io.File
import java.awt.event.ActionListener
import java.awt.event.MouseListener
import java.awt.event.ItemListener
import javax.imageio.ImageIO
import javax.swing.AbstractButton
import javax.swing.JButton
import javax.swing.JComboBox
import javax.swing.JList
import javax.swing.JRadioButton
import javax.swing.JSpinner
import javax.swing.SwingUtilities
import javax.swing.ImageIcon
import javax.swing.text.JTextComponent
import javax.swing.Timer
import javax.swing.event.ChangeListener
import javax.swing.event.DocumentListener
import javax.swing.event.ListSelectionListener

import os
import os.path
import threading

import inspect

from gvsig import getResource

from org.gvsig.tools.swing.api import ToolsSwingLocator
from org.gvsig.tools.task import TaskStatus
from org.gvsig.tools.observer import Observer
from org.gvsig.tools import ToolsLocator
import org.gvsig.tools.swing.api.Component

from com.jeta.open.registry import JETARegistry
from com.jeta.open.resources import ResourceLoader
from com.jeta.open.resources import AppResourceLoader
from org.gvsig.scripting import ScriptingLocator
from java.net import URL
from java.net import URLClassLoader
from jarray import array


class FormPanelResourceLoader(AppResourceLoader):
  def __init__(self, *urls):
    AppResourceLoader.__init__(self)
    classloader = URLClassLoader(array(urls, URL))
    self.setClassLoader(classloader)

  def loadImage(self, imageName):
    url = AppResourceLoader.loadImage(self, imageName)
    return url
    

class ListenerAdapter(object):
  def __init__(self,function,componentName=None):
    self.function = function
    self.synchronous  = True
    if componentName == None:
      self.componentName = self.function.__name__
    else:
      self.componentName = componentName
    x = getattr(function,"im_func",function)
    x.setSynchronous = self.setSynchronous
  def setSynchronous(self, value):
    self.synchronous = value
  def __call__(self, *args):
    if self.synchronous:
      self.function(*args)
    else:
      threading.Thread(target=self.function, name=self.componentName, args=args).start()

#----------------
# Falla invocar a ListenerAdapter.__init__(self,function,componentName)
# por que dice que self no es un ListenerAdapter.
# De momento duplico el codigo de ListenerAdapter incrustandolo en esta clase.
class ActionListenerAdapter_Upss(ListenerAdapter, java.awt.event.ActionListener):
  def __init__(self,function,componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def actionPerformed(self,*args):
    #print "ActionListenerAdapter %s %s" % (self.componentName, args[0])
    self(*args)

class ActionListenerAdapter(java.awt.event.ActionListener):
  def __init__(self,function,componentName=None):
    self.function = function
    self.synchronous  = True
    if componentName == None:
      self.componentName = self.function.__name__
    else:
      self.componentName = componentName
    x = getattr(function,"im_func",function)
    x.setSynchronous = self.setSynchronous
  def setSynchronous(self, value):
    self.synchronous = value
  def __call__(self, *args):
    if self.synchronous:
      self.function(*args)
    else:
      threading.Thread(target=self.function, name=self.componentName, args=args).start()

  def actionPerformed(self,*args):
    #print "ActionListenerAdapter %s %s" % (self.componentName, args[0])
    self(*args)


class ChangeListenerAdapter(ListenerAdapter, javax.swing.event.ChangeListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def stateChanged(self,*args):
    #print "ChangeListenerAdapter %s %s" % (self.componentName, args[0])
    self(*args)

class DocumentListenerAdapter(ListenerAdapter, javax.swing.event.DocumentListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def insertUpdate(self,*args):
    #print "DocumentListenerAdapter %s" % self.componentName
    self.function(*args)
  def removeUpdate(self,*args):
    #print "DocumentListenerAdapter %s" % self.componentName
    self(*args)
  def changedUpdate(self,*args):
    #print "DocumentListenerAdapter %s" % self.componentName
    self(*args)

class ItemListenerAdapter(ListenerAdapter, java.awt.event.ItemListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def itemStateChanged(self,*args):
    #print "ItemListenerAdapter %s %s" % (self.componentName, args[0])
    self(*args)

class ListSelectionListenerAdapter(ListenerAdapter, javax.swing.event.ListSelectionListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def valueChanged(self,*args):
    #print "ListSelectionListenerAdapter %s %s" % (self.componentName, args[0])
    self(*args)

class FocusGainedListenerAdapter(ListenerAdapter, java.awt.event.FocusListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def focusGained(self,*args):
    #print "focusGained %s %s" % (self.componentName, args[0])
    self(*args)
  def focusLost(self,*args):
    #print "focusLost %s %s" % (self.componentName, args[0])
    pass

class FocusLostListenerAdapter(ListenerAdapter, java.awt.event.FocusListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def focusGained(self,*args):
    pass
  def focusLost(self,*args):
    self(*args)

class MouseListenerAdapter(ListenerAdapter, java.awt.event.MouseListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def mouseClicked(self,*args):
    self(*args)
  def mouseEntered(self,*args):
    self(*args)
  def mouseExited(self,*args):
    self(*args)
  def mousePressed(self,*args):
    self(*args)
  def mouseReleased(self,*args):
    self(*args)

class KeyPressedListenerAdapter(ListenerAdapter, java.awt.event.KeyListener):
  def __init__(self,function, componentName=None):
    ListenerAdapter.__init__(self,function,componentName)
  def keyTyped(self,*args):
    pass
  def keyPressed(self,*args):
    try:
      self(*args)
    except java.lang.Throwable, t:
      pass
  def keyReleased(self,*args):
    pass

class FunctionRunnable(java.lang.Runnable):
  def __init__(self,fn, *args):
    self.__fn = fn
    self.__args = args

  def run(self):
    self.__fn(*self.__args)

  def __call__(self):
    self.__fn(*self.__args)


class ProgressBarWithTaskStatus(Observer):
  def __init__(self, name, progressBar, labelProgress=None):
    self.taskStatus = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(name)
    self.progressBar = progressBar
    self.labelProgress = labelProgress
    self.progressBar.setMinimum(0)
    self.progressBar.setMaximum(100)
    self.progressBar.setValue(0)
    self.taskStatus.addObserver(self)

  def getTaskStatus(self):
    return self.taskStatus

  def update(self, taskStatus, notification):
    if not javax.swing.SwingUtilities.isEventDispatchThread():
      javax.swing.SwingUtilities.invokeLater(
        FunctionRunnable(
          self.updateGUI,
          taskStatus.isRunning(),
          taskStatus.getCompleted(),
          taskStatus.getLabel()
        )
      )
    else:
      self.updateGUI(
        taskStatus.isRunning(),
        taskStatus.getCompleted(),
        taskStatus.getLabel()
      )

  def updateGUI(self, isRunning, current, label):
    if not isRunning:
        self.progressBar.setIndeterminate(False)
        self.progressBar.setValue(100)
        self.labelProgress.setText("")
        return
    self.progressBar.setIndeterminate(self.taskStatus.isIndeterminate())
    self.progressBar.setValue(current)
    if self.labelProgress != None:
      self.labelProgress.setText(label)

def load_image(afile):
  if not isinstance(afile,java.io.File):
    if isinstance(afile,tuple) or isinstance(afile,list):
      afile = getResource(*afile)
    afile = java.io.File(str(afile))
  return javax.imageio.ImageIO.read(afile)

def load_icon(afile):
  if not isinstance(afile,java.io.File):
    if isinstance(afile,tuple) or isinstance(afile,list):
      afile = getResource(*afile)
    afile = java.io.File(str(afile))
  return javax.swing.ImageIcon(javax.imageio.ImageIO.read(afile))

class ComboItem(object):
  def __init__(self, label="", value=None):
    self.__label = label
    self.__value = value

  def getLabel(self):
    return self.__label

  def getValue(self):
    return self.__value

  __str__ = getLabel
  __repr__ = getLabel

class FormComponent(object):

  def load_image(self, afile):
    return load_image(afile)

  def load_icon(self, afile):
    return load_icon(afile)

  def autobind(self):
    members = inspect.getmembers(self)
    for methodName, method in members:
      if methodName.endswith("_click"):
        name = methodName[0:-len("_click")]
        component = getattr(self,name, None)
        if isinstance(component, javax.swing.JComboBox):
          component.addActionListener(ActionListenerAdapter(method,methodName))
        elif isinstance(component, javax.swing.AbstractButton):
          component.addActionListener(ActionListenerAdapter(method,methodName))

      elif methodName.endswith("_change"):
        name = methodName[0:-len("_change")]
        component = getattr(self,name, None)
        if isinstance(component, javax.swing.JComboBox):
          component.addItemListener(ItemListenerAdapter(method,methodName))
        elif isinstance(component, javax.swing.JList):
          component.addListSelectionListener(ListSelectionListenerAdapter(method,methodName))
        elif isinstance(component, javax.swing.JRadioButton):
          component.addItemListener(ItemListenerAdapter(method,methodName))
        elif isinstance(component, javax.swing.JSpinner):
          component.addChangeListener(ChangeListenerAdapter(method,methodName))
        elif isinstance(component, javax.swing.text.JTextComponent):
          component.getDocument().addDocumentListener(DocumentListenerAdapter(method,methodName))
        elif isinstance(component, javax.swing.AbstractButton):
          component.addActionListener(ActionListenerAdapter(method,methodName))

      elif methodName.endswith("_perform"):
        name = methodName[0:-len("_perform")]
        component = getattr(self,name, None)
        if isinstance(component, javax.swing.Timer):
          component.addActionListener(ActionListenerAdapter(method,methodName))

      elif methodName.endswith("_focusGained"):
        name = methodName[0:-len("_focusGained")]
        component = getattr(self,name, None)
        if component!=None:
          addFocusListener = getattr(component,"addFocusListener",None)
          if addFocusListener !=None:
            addFocusListener(FocusGainedListenerAdapter(method,methodName))

      elif methodName.endswith("_focusLost"):
        name = methodName[0:-len("_focusLost")]
        component = getattr(self,name, None)
        if component!=None:
          addFocusListener = getattr(component,"addFocusListener",None)
          if addFocusListener !=None:
            addFocusListener(FocusLostListenerAdapter(method,methodName))

      elif methodName.endswith("_mouseClick"):
        name = methodName[0:-len("_mouseClick")]
        component = getattr(self,name, None)
        if component!=None:
          addMouseListener = getattr(component,"addMouseListener",None)
          if addMouseListener !=None:
            addMouseListener(MouseListenerAdapter(method,methodName))

      elif methodName.endswith("_keyPressed"):
        name = methodName[0:-len("_keyPressed")]
        component = getattr(self,name, None)
        if component!=None:
          addKeyListener = getattr(component,"addKeyListener",None)
          if addKeyListener != None:
            addKeyListener(KeyPressedListenerAdapter(method,methodName))


def fixFormPanelResourceLoader():
  appResourceLoader = JETARegistry.lookup(ResourceLoader.COMPONENT_ID)
  if not isinstance(appResourceLoader,FormPanelResourceLoader):
    # Ojo, si no llamamos a este initialize, la primera vez
    # que se carga un formulario no carga los recursos
    from com.jeta.forms.defaults import DefaultInitializer
    DefaultInitializer.initialize()

    f1 = ScriptingLocator.getManager().getUserFolder().getFile()
    f2 = java.io.File(ScriptingLocator.getManager().getUserFolder().getFile().getParentFile().getParentFile(),"scripts")
    formPanelResourceLoader = FormPanelResourceLoader(f1.toURL(),f2.toURL())
    JETARegistry.rebind(ResourceLoader.COMPONENT_ID, formPanelResourceLoader)


class FormPanel(FormComponent):

  def __init__(self,formfile=None):
    FormComponent.__init__(self)
    fixFormPanelResourceLoader()
    self._panel = None
    if formfile!=None:
      self.load(formfile)

  def getRootPane(self):
    return self.asJComponent().getParent().getParent()

  def getPreferredSize(self):
    return self.asJComponent().getPreferredSize()

  def setPreferredSize(self, withOrDimension, height=None):
    if height == None:
      self.asJComponent().setPreferredSize(withOrDimension)
    else:
      self.asJComponent().setPreferredSize(java.awt.Dimension(withOrDimension,height))

  def getPanel(self):
    return self.asJComponent()

  def asJComponent(self):
    return self._panel

  def hide(self):
    self._panel.setVisible(False)

  def __getattr__(self, name):
    if name in ("__members__", "__methods__"):
      raise AttributeError("FormPanel",name)
    attr = self._panel.getComponentByName(name)
    if attr == None:
      raise AttributeError("FormPanel",name)
    return attr

  def load(self, formfile):
    if not isinstance(formfile,java.io.File):
      if isinstance(formfile,tuple) or isinstance(formfile,list):
        formfile = getResource(*formfile)
      formfile = java.io.File(str(formfile))
    #print "FormPanel.load(%s)" % formfile
    self._panel = com.jeta.forms.components.panel.FormPanel( java.io.FileInputStream(formfile) )
    #print "FormPanel.load: _panel=%s" % self._panel
    self.autobind()

  def btnClose_click(self,*args):
    self.hide()

  def showWindow(self, title):
    self._panel.setVisible(True)
    windowManager = ToolsSwingLocator.getWindowManager()
    windowManager.showWindow(self.asJComponent(),title, windowManager.MODE.WINDOW)

  def showTool(self, title):
    self._panel.setVisible(True)
    windowManager = ToolsSwingLocator.getWindowManager()
    windowManager.showWindow(self.asJComponent(),title, windowManager.MODE.TOOL)

  def showDialog(self, title):
    self._panel.setVisible(True)
    windowManager = ToolsSwingLocator.getWindowManager()
    windowManager.showWindow(self._panel,title, windowManager.MODE.DIALOG)

