
from gvsig import *
from commonsdialog import *

import os
import os.path
import shutil
import sys
import subprocess 
import threading
import logging

from libs.formpanel import FormPanel

from java.awt import Dimension

import pynliner


class CSSInliner(object):
  def __init__(self):
    pass
    
  def getsafestr(self, s):
    s = repr(s)
    s = s.replace("\\n","\n")
    s = s.replace("\\'","'")
    
    s = s[2:-1]
    return s

  def writetofile(self, html,pathname, mode="w"):
      f=open("/tmp/cssinliner.tmp",mode)
      f.write(html)
      f.close()
      shutil.copyfile("/tmp/cssinliner.tmp", pathname)

  def replaces(self, html):
    html=html.replace('<div>JavaScript is disabled on your browser.</div>','')
    html=html.replace('background-color: #fff;','')
    html=html.replace('background-color: #fff"','"')
    html=html.replace('class="blockList" style="list-style-type: disc; ','class="blockList" style="list-style-type: none; ')
    html=html.replace('class="blockListLast" style="list-style-type: disc;', 'class="blockListLast" style="list-style-type: none;')
    html=html.replace('class="inheritance" style="list-style-type: disc;','class="inheritance" style="list-style-type: none;')
    html=html.replace(' border-top: none','')
    html=html.replace('font-size: 1.1em;', 'font-size: medium;')
    html=html.replace('font-size: 1.2em;', 'font-size: medium;')
    html=html.replace('font-size: 1.3em;', 'font-size: medium;')
    html=html.replace('font-size: 1.4em;', 'font-size: large;')
    html=html.replace('font-size: 1.1em"', 'font-size: medium"')
    html=html.replace('font-size: 1.2em"', 'font-size: medium"')
    html=html.replace('font-size: 1.3em"', 'font-size: medium"')
    html=html.replace('font-size: 1.4em"', 'font-size: large"')
    html=html.replace('font-size: 76%;', 'font-size: small;')
    return html
  
  def __call__(pathname):
    self.process(pathname)

  def process(self, pathname):
    """
    Para que se vean correctamente los javadocs en el JavaHelp
    hay que transformar las refrencias al CSS a sentencias css embebidas
    en cada tag.
    """
    html=pynliner.fromURL("file://"+pathname)
    
    """
    Ademas hay algunas cosas del CSS que no se ven bien en el visor del
    JavaHelp, asi que las parcheamos reemplazandolas por otros valores.
    """
    html = self.replaces(html)
    
    try:
      self.writetofile(html,pathname)
    except UnicodeEncodeError:
      try:
        html = html.encode('ISO-8859-1')
        self.writetofile(html,pathname)
      except:
        try:
          self.writetofile(self.getsafestr(html),pathname)
        except:
          pass
    except Exception,ex:
      print "\n>>> Error procesando fichero. " + str(ex)
    except:
      print "\n>>> Error procesando fichero."
    


class MakeDocs(FormPanel, threading.Thread):
  def __init__(self,workspace,projects,outputfolder):
    threading.Thread.__init__(self)
    FormPanel.__init__(self,script.getResource("makedocs.xml"))
    #self.getPanel().setPreferredSize(Dimension(800,190))
    self.canceled = False

    self.workspace = workspace
    self.projects = projects
    self.outputfolder = outputfolder
    self.txtWorkspace.setText(workspace)
    self.txtOutputFolder.setText(outputfolder)

  def findJavaSources(self,workspace,project):
    projectFolder = os.path.join(workspace,project)
    sources = list()
    #print projectFolder
    for root, dirs, files in os.walk(projectFolder):
        for file in files:
            if file == "pom.xml":
              if root[-5:] != ".main":
                javaSources = os.path.join(root,"src","main","java")
                if os.path.isdir(javaSources):
                  sources.append(javaSources)
                  self.message2(root)
    return sources
  
  def findJavadocSources(self,workspace,projects):
    sources = list()
    for project, url in projects:
      sources.extend(self.findJavaSources(workspace,project))
    return sources
  
  def calculateCountFromSources(self,sources):
    countfiles = 0
    folders = set()
    for sourceFolder in sources:
      for root, dirs, files in os.walk(sourceFolder):
        for f in files:
            if f.endswith(".java"):
              countfiles+=1
              self.message2("[%05d] %s" %  (countfiles, os.path.join(root,f)))
        if len(files)>0:
          package = root[len(sourceFolder)+1:]
          folders.add(package)
  
    return countfiles, len(folders)

  def calculateHTMLFileList(self,htmlroot, listfname):
    listfile= open(listfname,"w")
    countfiles = 0
    for root, dirs, files in os.walk(htmlroot):
      for f in files:
        if f.startswith("package-"):
          continue
        if f.endswith(".html"):
          countfiles+=1
          listfile.write(os.path.join(root,f))
          listfile.write("\n")
          self.message2("[%05d] %s" %  (countfiles, os.path.join(root,f)))
    listfile.close()
    return countfiles

  def message(self,msg):
    self.lblStatus.setText(msg)
    
  def message2(self,msg):
    self.lblStatus2.setText(msg)

  def mkjavadoc(self,workspace,projects, outputpath):
    try:
      self.pgbProgreso.setIndeterminate(True)
      self.message("Creando carpeta de salida...")
      if not os.path.exists(outputpath):
        os.makedirs(outputpath)
    
      os.chdir(outputpath)
      if not os.path.exists("html"):
        os.makedirs("html")
      os.chdir("html")
  
      if self.chkGenerarJavadocs.isSelected():
        self.message("Eliminando javadoc existentes...")
        os.chdir("..")
        shutil.rmtree("html",True)
        os.makedirs("html")
        os.chdir("html")
  
        self.message("Localizando fuentes...")
        sources = self.findJavadocSources(workspace,projects)
    
        self.message("Preparando procesado...")
        maxfiles, maxpackages = self.calculateCountFromSources(sources)
        
        argsfile = file("javadoc_args","w")
        argsfile.write("-nonavbar\n")
        argsfile.write("-encoding ISO-8859-1\n")
        argsfile.write("-subpackages org\n")
        argsfile.write("-sourcepath ")
        for source in sources:
          argsfile.write(":%s" % source)
        argsfile.write("\n")
        argsfile.close()
    
        proc = subprocess.Popen(["javadoc", "@javadoc_args"], stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
        stdoutprocess = proc.stdout 
        generatingcount = 0
        loadingcount=0

        self.pgbProgreso.setMaximum(maxpackages)
        self.pgbProgreso.setValue(0)
        self.pgbProgreso.setIndeterminate(False)
        
        for line in stdoutprocess:
          if self.canceled:
            break
          #print line[:-1]
          if ": error:" in line :
            self.message("Procesando fuentes...")
            self.message2(line)
                  
          elif line.startswith("Generating "):
            self.message("Generando javadocs...")
            if generatingcount == 0:
              self.pgbProgreso.setMaximum(maxfiles + maxpackages*3 + 9)
            self.message2(line[11:-9])
            if "/package-" in line:
              generatingcount+=1
            else:
              if os.path.basename(line[:-4]).count(".")==1:
                generatingcount +=1
            self.pgbProgreso.setValue(generatingcount)
                
          elif line.startswith("Loading source files for package "):
            self.message("Cargando fuentes...")
            loadingcount+=1
            self.pgbProgreso.setValue(loadingcount)
            self.message2(line[33:])
    
      if self.chkProcesarCSS.isSelected():
        self.message("Preparando procesdado de HTMLs (CSS inliner)...")
        self.message2("")
        path=os.path.join(outputpath,"html","org")
        
        listfname = script.getResource("htmls.txt").getAbsolutePath()
        lastfname = script.getResource("lasthtml.txt").getAbsolutePath()
        if self.chkContinuarProcesoAnterior.isSelected() and os.path.exists(listfname) and os.path.exists(lastfname):
          ff = open(lastfname,"r")
          skipto = ff.read()
          ff.close()
          if skipto in (None,"","\n"):
            skipto = None
          ff = open(listfname,"r")
          htmlscount = 0
          for fname in ff:
            htmlscount +=1
          ff.close()
        else:
          skipto = None
          htmlscount = self.calculateHTMLFileList(path,listfname)
        
        self.pgbProgreso.setMaximum(htmlscount)
        self.pgbProgreso.setValue(0)
        self.pgbProgreso.setIndeterminate(False)
        self.message("Procesando HTMLs (CSS inliner)...")
        cssinliner = CSSInliner()
        htmlscount = 0
        listfile = open(listfname,"r")
        for fname in listfile:
          htmlscount+=1
          self.message2(fname)
          self.pgbProgreso.setValue(htmlscount)
          if skipto != None:
            if skipto != fname:
              continue
            skipto = None
          if self.canceled:
            ff = open(lastfname,"w")
            ff.write(fname)
            ff.close()
            break
          cssinliner.process(fname)

      self.message("Proceso terminado")
      self.message2("")
      self.pgbProgreso.setValue(self.pgbProgreso.getMaximum())
      if self.canceled:
        print "Proceso cancelado"
        
    except Exception, ex:
      self.message("Proceso abortado")
      self.message2(str(ex))
      print str(ex)
      logging.exception("Proceso abortado")

  def btnSelectWorkspace_click(self, *args):
    f = openFolderDialog("Selecciona la carpeta del workspace")
    if f == None or len(f)<1:
      return
    self.txtWorkspace.setText(f[0].getAbsolutePath())
  
  def btnSelectOutputFolder_click(self, *args):
    f = openFolderDialog("Selecciona la carpeta de salida")
    if f == None or len(f)<1:
      return
    self.txtOutputFolder.setText(f[0].getAbsolutePath())
  
  def btnCerrar_click(self,*args):
    self.canceled = True
    self.hide()

  def btnProcesar_click(self,*args):
    self.btnProcesar.setEnabled(False)
    self.btnCerrar.setText("Cancelar")
    self.start()

  def run(self):
    self.mkjavadoc(
      self.workspace,
      self.projects, 
      self.outputfolder
    )
    # Falla al volverse a lanzar el proceso por que no se
    # a rearmado correctamente el thread. Asi que dejo
    # desactivado el boton.
    #self.btnProcesar.setEnabled(True)


def main(*args):
  workspace = "/home/jjdelcerro/datos/devel"
  outputfolder = "/home/jjdelcerro/datos/temp/javadocs"
  projects = (
    ("org.gvsig.app.document.layout2.app",None),
    ("org.gvsig.attributeeditor",None),
    ("org.gvsig.catalog",None),
    ("org.gvsig.chart",None),
    ("org.gvsig.legend.dotdensity.app.mainplugin",None),
    ("org.gvsig.raster.principalcomponents",None),
    ("org.gvsig.complexlegend",None),
    ("org.gvsig.legend.graduatedsymbols.app.mainplugin",None),
    ("org.gvsig.raster.reproject",None),
    ("org.gvsig.legend.proportionalsymbols.app.mainplugin",None),
    ("org.gvsig.raster.roimask",None),
    ("org.gvsig.derivedgeometries",None),
    ("org.gvsig.legend.quantitybycategory.app.mainplugin",None),
    ("org.gvsig.raster.tasseledcap",None),
    ("org.gvsig.desktop",None),
    ("org.gvsig.legend.vectorfilterexpression.app.mainplugin",None),
    ("org.gvsig.raster.tilecache",None),
    ("org.gvsig.mapsheets.app",None),
    ("org.gvsig.raster.tools",None),
    ("org.gvsig.projection.api",None),
    ("org.gvsig.dyschromatopsia",None),
    ("org.gvsig.projection.jcrs",None),
    ("org.gvsig.scripting",None),
    ("org.gvsig.publish",None),
    ("org.gvsig.expressionfield",None),
    ("org.gvsig.raster",None),
    ("org.gvsig.sld",None),
    ("org.gvsig.gazetteer",None),
    ("org.gvsig.tools",None),
    ("org.gvsig.vectorediting",None),
    ("org.gvsig.geoprocess",None),
    ("org.gvsig.raster.georeferencing",None),
    ("org.gvsig.vectorediting.symmetry",None),
    ("org.gvsig.hyperlink.app",None),
    ("org.gvsig.toolbox","http://devel.gvsig.org/svn/gvsig-toolbox/org.gvsig.toolbox/trunk/org.gvsig.toolbox/"),
  )
  makedocs = MakeDocs(workspace,projects,outputfolder)
  makedocs.showWindow("Crear javadocs")
  #makedocs.run()
    


