#!/usr/bin/python

import sys, os, fnmatch
from sys import exit
from shutil import rmtree, move
from os import chdir as cd
from os import makedirs as mkdir
from os.path import dirname, exists
from os import remove

import ConfigParser
import StringIO
import textwrap
import re
import urlparse

def unzip(zipfile):
  cmd = "unzip %s 2>/dev/null" % zipfile
  print cmd
  os.system(cmd)

def find_all(name, path):
    result = []
    for root, dirs, files in os.walk(path):
        if name in files:
          result.append(os.path.join(root, name))
    return result

def find_match(pattern, path):
    result = []
    for root, dirs, files in os.walk(path):
        for name in files:
            if fnmatch.fnmatch(name, pattern):
                result.append(os.path.join(root, name))
    return result

def find(name,path):
  result = find_all(name,path)
  if len(result)==1:
    return result[0]
  return None

def fixurls(rest,prefix):
  def is_relative(url):
    return not bool(urlparse.urlparse(url).netloc)

  searchs=(
    "[ \\t]*..[ \\t]*image::[ \\t]*(.*)", # .. image:: file1.png
    "[ \\t]*..[ \\t]*figure::[ \\t]*(.*)", # .. figure:: file1.png
    "[ \\t]*..[ \\t]*include::[ \\t]*(.*)", # .. include:: file1.png
    "[ \\t]*..[ \\t]*_[^:]*:[ \\t]*(.*)", # .. _Python home page: file
    "`[^<]*<([^>]*)>`_" # See the `Python home page <file>`_ for info.
  )

  for search in searchs:
    out = StringIO.StringIO()
    last=0
    for x in re.finditer(search,rest):
      url = x.group(1)
      start = x.start(1)
      end = x.end(1)
      #print "url='%s', relative=%s, start=%s, end=%s" % (url,is_relative(url),start,end)
      if is_relative(url):
        out.write(rest[last:start])
        out.write(prefix)
        out.write(url)
        last=end
    out.write(rest[last:])
    rest=out.getvalue()
  return rest
  
class Properties(object):
  def __init__(self,pathname=None):
    self.config = None
    self.values = dict()
    if pathname!=None:
      self.load(pathname)

  def load(self,pathname):
    f=open(pathname)
    ss=f.read()
    f.close()
    sio=StringIO.StringIO("[All]\n"+ss)
    self.config = ConfigParser.RawConfigParser()
    self.config.readfp(sio)

  def __getitem__(self,name):
    if self.values.has_key(name):
      return self.values[name]
    value = self.config.get("All",name)
    if value == None:
      return None
    if "\\u" in value:
      try:
        value = value.decode('unicode-escape').encode("utf8")
      except:
        pass
    return value.replace("\\:",":").replace("\\n","\n")

  def __setitem__(self, name,value):
    self.values[name] = value

def extract_package(package_basename, pool, package_path):
  print "Searching package '%s'" % package_basename
  print "POOL '%s'\n" % pool
  pkg=find(package_basename,pool)
  if pkg == None :
    print "Package file '%s' not found or duplicated in pool." % package_basename
    exit(-1)

  print "Found package '%s'" % pkg
  
  if exists(package_path):
    rmtree(package_path)
  mkdir(package_path)
  cd(package_path)

  print "Extracting package in '%s'\n" % package_path
  unzip(pkg)
  return pkg



def load_properies(package_path):

  cd(package_path)
  print "Searching 'package.info' in '%s'" % package_path
  package_info_file=find("package.info",".")
  if package_info_file == None:
    print "Can't locate package info"
    exit(-3)

  package_info = Properties(package_info_file)
  print "Found 'package.info' in '%s'" % package_info_file
  package_info["sources"]= dirname(package_info_file)
  package_info["package_rst"] = package_info["sources"] + "/package.rst"

  if package_info["official"]=="true" :
    package_info["type"]="Official"
  else:
    package_info["type"]="Community"

  return package_info

def create_code_browser(package_path,package_info):
  cd(package_path)

  print "Creating code browser"
  rst = """
:orphan:

Code Browser: %(code)s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. raw:: html

    <style>
    .ap { color: black; text-decoration: none; } 
    /*  Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>  */
    .hljs {   display: block;   overflow-x: auto;   padding: 0.5em;   background: white;   color: black; }  .hljs-comment, .hljs-quote, .hljs-variable {   color: #008000; }  .hljs-keyword, .hljs-selector-tag, .hljs-built_in, .hljs-name, .hljs-tag {   color: #00f; }  .hljs-string, .hljs-title, .hljs-section, .hljs-attribute, .hljs-literal, .hljs-template-tag, .hljs-template-variable, .hljs-type, .hljs-addition {   color: #a31515; }  .hljs-deletion, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-meta {   color: #2b91af; }  .hljs-doctag {   color: #808080; }  .hljs-attr {   color: #f00; }  .hljs-symbol, .hljs-bullet, .hljs-link {   color: #00b0e8; }   .hljs-emphasis {   font-style: italic; }  .hljs-strong {   font-weight: bold; }
    </style>
    <script>
    function makeHttpObject() {
      try {
        return new XMLHttpRequest();
      } catch (error) {
      }
      try {
        return new ActiveXObject("Msxml2.XMLHTTP");
      } catch (error) {
      }
      try {
        return new ActiveXObject("Microsoft.XMLHTTP");
      } catch (error) {
      }
      throw new Error("Could not create HTTP request object.");
    }

    function simpleHttpRequest(url, success, failure) {
      var request = makeHttpObject();
      request.open("GET", url, true);
      request.send(null);
      request.onreadystatechange = function() {
        if (request.readyState == 4 ) {
          if( request.status == 200) {
            success(request.responseText);
          } else if( failure ) {
            failure(request.status, request.statusText);
          } else {
              console.log("failure to download '"+url+"'\\nStatus code" + request.status + ", " + request.statusText)
          }
        }
      };
    }

    function loadfile(name) {
      baseurl="http://downloads.gvsig.org/download/web/scriptcatalog/source/packages"
      console.log(window.location.path)
      url=baseurl +"/" + name
      tag_filename = document.getElementById("filename")
      tag_filename.innerHTML = name
      tag_filename.href = "code_browser.html?" + name
      simpleHttpRequest(
        url,
        function(text) {
          //console.log("download ok")
          var result = hljs.highlightAuto(text);
          tag_code = document.getElementById("code")
          tag_code.innerHTML = result.value
          add_line_numbers(tag_code)
        }
      )
      document.getElementById("codebrowser").style.display = 'none'
    }
    function toggleCodeBrowser() {
      tag = document.getElementById('codebrowser')
        if( tag.style.display == "none" ) {
          tag.style = "display: block; position: absolute; background-color: #f9f9f9; min-width: 360px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1; "
        } else {
          tag.style.display = 'none'
        }
    }
    function add_line_numbers(el) {
      var lines = el.innerHTML.split('\\n');
      el.style.position = "relative";
      el.style.padding = "0";
      if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) // Chrome cuts off 3 digit line numbers on the left
        var new_contents = "<ol style='margin-left: .5em'>"; // if we don't add a .5em margin
      else
        var new_contents = "<ol>";
      for(var i=0; i<lines.length; i++) {
        new_contents += "<li><pre style='display: inline; border-width: 0px; padding: 0px;'>"+lines[i]+"</pre></li>";
      }
      new_contents += "</ol>";
      el.innerHTML = new_contents;
    }
    </script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js"></script>
    <div>
      <button onclick="toggleCodeBrowser()">Select source</button>
      <div width="200" id="codebrowser" >
        <ul>
""" % package_info

  files = find_match("*",".")
  files.sort()
  for f in files:
    name,ext = os.path.splitext(f.lower())
    if not (ext in (".class",".inf",".jar",".zip") or name.endswith(".directory") ):
      if ext in (".py",".txt",".rst",".xml", ".info",".groovy",".r",".properties",".csv"):
        rst += '    <li><a class="ap" href="javascript:void(0);"onclick="loadfile(\'%s/%s\')">%s</a></li>\n' % (
          package_info["code"], f[2:],f[2:]
        )
      else:
        rst += '    <li class="ap">%s</li>\n' %  f[2:]
  rst +="""
          </ul>
        </div>
        <a style="color: black; text-decoration: none;" id="filename" href=""></a>
        <a onclick="window.prompt('To copy the address to the clipboard press Ctrl-C and ENTER      ', document.getElementById('filename').href)"><img style="cursor: pointer;" src="../../../../link.png" title="Link to this page"/></a>
      </div>
      <pre>
        <code id="code">
        \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
        </code>
      </pre>
      <script>
      function main() {
        var urlHack = document.createElement('a');
        urlHack.href = window.location.href
        search=urlHack.search.substr(1) // Quitamos el ?
        if( search!="" ) {
          loadfile(search)
        }
      }
      main()
      </script>
"""

  f=open("code_browser.rst","w")
  f.write(rst)
  f.close()

def create_package_summary(package_path, package_info):

  cd(package_path)

  print "Creating package summary"
  description = list()
  for line in package_info["description"].split("\n"):
    if len(line)>100:
      description.extend(textwrap.wrap(line,100, drop_whitespace=True,replace_whitespace=False))
    else:
      description.append(line)
  description = "\n    ".join(description)
  package_info["description"] = description

  package_info["code_browser"]="%s/code_browser.html" % (package_info["code"])
  files = find_match("*.py",".")
  files.sort()
  for f in files:
    if not f.endswith("__init__.py"):
      package_info["code_browser"]="%s/code_browser.html?%s/%s" % (package_info["code"],package_info["code"], f)
      break

  rst = """
%(name)s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. toctree::
   :hidden:
   :maxdepth: 10

.. toctree::
   :maxdepth: 1

.. raw:: html

    <table border="0" cellpadding="2" cellspacing="2">
      <tbody>
        <tr>
          <td nowrap valign="top"><b>Package file:</b></td>
          <td nowrap valign="top"><a href="%(package_url)s">%(basename)s</a></td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Code name:</b></td>
          <td nowrap valign="top">%(code)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Version: </b></td>
          <td nowrap valign="top">%(version)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Version of gvSIG:</b></td>
          <td nowrap valign="top">%(gvSIG-version)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Type: </b></td>
          <td nowrap valign="top">%(type)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Owner:</b></td>
          <td nowrap valign="top">%(owner)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>State:</b></td>
          <td nowrap valign="top">%(state)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Home page:</b></td>
          <td nowrap valign="top"><a href="%(web-url)s">%(web-url)s</a></td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Operating system:</b></td>
          <td nowrap valign="top">%(operating-system)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Categories:</b></td>
          <td valign="top">%(categories)s</td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Sources:</b></td>
          <td nowrap valign="top"><a href="%(code_browser)s">Browse</a></td>
        </tr>
        <tr>
          <td nowrap valign="top"><b>Description:</b></td>
          <td valign="top"></td>
        </tr>
        <tr>
          <td colspan="2" rowspan="1" valign="top"><pre>%(description)s</pre></td>
        </tr>
      </tbody>
    </table>

""" % package_info


  if exists(package_info["package_rst"]):
    print "Found 'package.rst', adding to summary."

    f = open(package_info["package_rst"])
    package_rst_contents = f.read()
    f.close()
    package_rst_contents = fixurls(package_rst_contents, "%s/%s/" % (package_info["code"],package_info["code"]))
    #f = open(package_info["package_rst"],"w")
    #f.write(package_rst_contents)
    #f.close()
    #
    #rst += "\n.. include:: %s/%s\n\n" % (
    #  package_info["code"],
    #  package_info["package_rst"]
    #)
    rst += "\n\n" + package_rst_contents

  f=open(package_info["code"]+".rst","w")
  f.write(rst)
  f.close()

def main():
  POOL="/mnt/data0/public-files/gvsig-desktop-testing/pool"
  POOL_URL="http://downloads.gvsig.org/download/gvsig-desktop-testing/pool"
  
  PACKAGES_FOLDER="/mnt/data0/public-files/web/scriptcatalog/source/packages"

  if len(sys.argv)==2:
    package_basename=sys.argv[1]
  else:
    package_basename = os.environ.get('Pacckage_name')
  if package_basename in (None,""):
    print "Need a package name"
    exit(-4)

  print "\nAdding to scripts catalog package '%s'.\n" % package_basename

  package_path = PACKAGES_FOLDER+"/package.tmp"

  zip_path = extract_package(package_basename, POOL, package_path)
  
  package_info = load_properies(package_path)
  package_info["basename"] = package_basename
  package_info["package_url"]= zip_path.replace(POOL,POOL_URL,1)

  create_code_browser(package_path, package_info)
  create_package_summary(package_path, package_info)

  cd(package_path)
  package_code = package_info["code"]
  package_target = "%s/%s" % (PACKAGES_FOLDER, package_code)
  summary_target = "../%s.rst" % package_code
  if exists(summary_target):
    print "Removing existing old package summary"
    remove(summary_target)
  print "Install package summary"
  move("%s.rst" % package_code, summary_target)

  if exists(package_target):
    print "Removing old package"
    rmtree(package_target)
  print "Install new package"
  move(package_path, package_target)

main()
