# -- coding: utf-8 --
# ===========================================================================
# eXe 
# Copyright 2010-2011, Pedro Peña Pérez
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# ===========================================================================

import os
import mimetypes
from chardet import universaldetector
from chardet import latin1prober
import re
import sys
from bs4 import BeautifulSoup, UnicodeDammit
from urllib import quote, unquote
from exe.engine.freetextidevice import FreeTextIdevice
from exe.engine.resource import Resource
from exe.engine.path import Path
import logging

log = logging.getLogger(__name__)

class FixedLatin1Prober(latin1prober.Latin1Prober):
    """La clase Latin1Prober baja a la mitad la confidencia para mejorar los resultados de
     otros probers. Dejamos la confidencia en su valor real."""
    def get_confidence(self):
        return latin1prober.Latin1Prober.get_confidence(self)*2

class FixedUniversalDetector(universaldetector.UniversalDetector):
    """Para usar FixedLatin1Prober"""
    def __init__(self):
        from chardet.mbcsgroupprober import MBCSGroupProber # multi-byte character sets
        from chardet.sbcsgroupprober import SBCSGroupProber # single-byte character sets
        universaldetector.UniversalDetector.__init__(self)
        self._mCharSetProbers = [MBCSGroupProber(), SBCSGroupProber(), FixedLatin1Prober()]

def detect(aBuf):
    """Autodetecta la codificacion de una cadena usando FixedUniversalDetector"""
    u = FixedUniversalDetector()
    u.reset()
    u.feed(aBuf)
    u.close()
    return u.result
    
def relpath(path, start):
    """Implementa os.path.relpath independientemente del sistema y arregla un fallo cuando start una unidad en windows"""
    if sys.platform[:3] == 'win':
        if not hasattr(os.path,'relpath'):
            r = nt_relpath(path,start).replace(os.sep,os.altsep)
        else:
            r = os.path.relpath(path, start).replace(os.sep,os.altsep)
        if os.path.splitdrive(start)[1] in ['',os.curdir,os.sep,os.sep + os.curdir]:
            r = r.replace(os.pardir + os.altsep,'')
        return r
    else:
        return os.path.relpath(path, start)

curdir = '.'
def nt_relpath(path, start=curdir):
    """Implementa os.path.relpath para Windows ya que en python 2.5 no esta implementada"""

    from ntpath import abspath, splitunc, sep, pardir, join
    
    if not path:
        raise ValueError("no path specified")
    start_list = abspath(start).split(sep)
    path_list = abspath(path).split(sep)
    if start_list[0].lower() != path_list[0].lower():
        unc_path, rest = splitunc(path)
        unc_start, rest = splitunc(start)
        if bool(unc_path) ^ bool(unc_start):
            raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" % (path, start))
        else:
            raise ValueError("path is on drive %s, start on drive %s" % (path_list[0], start_list[0]))
    # Work out how much of the filepath is shared by start and path.
    for i in range(min(len(start_list), len(path_list))):
        if start_list[i].lower() != path_list[i].lower():
            break
    else:
        i += 1

    rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
    if not rel_list:
        return curdir
    return join(*rel_list)

class Link:
    def __init__(self, url, relative, referrer, tag = None, key = None, match = None):
        self.url = url
        self.referrer = referrer
        self.tag = tag
        self.key = key
        self.relative = relative
        self.match = match
    def __repr__(self):
        if self.tag and self.tag.name:
            return "<%s %s=%s>" % (self.tag.name,self.key,str(self.url))
        else:
            return "<%s>" % (str(self.url))

class Url:
    def __init__(self, path, start='.'):
        self.path = path
        self.start = start
        self.relpath = relpath(self.path,self.start)
        parent = os.path.split(self.relpath)[0]
        self.parentpath = u"." if parent == u"" else parent
        self.basename = os.path.basename(self.relpath)
        if os.path.isdir(self.path):
            self.type = 'dir'
        elif os.path.isfile(self.path):
            self.type = 'file'
        self.mime, self.dataencoding = mimetypes.guess_type(self.path)
        self.links = []
        self.plinks = []
        self.rlinks = set()
        self.soup = None
        self.content = None

        self.contentUpdated = []
        self.l = unquote(self.relpath)
        self.absl = self.start + os.path.sep + self.l
    def setSoup(self,soup):
        if self.mime == 'text/html':
            self.soup = soup
    def getSoup(self):
        return self.soup
    def setContent(self,content,encoding):
        self.content = content
        self.con
tentEncoding = encoding
    def getContent(self):
        return self.content
    def createNode(self,parent, name = None):
        self.node = parent.createChild()
        self.node.setTitle(name if name else self.basename)
    def createIdevice(self):
        self.idevice = FreeTextIdevice()
        self.idevice.edit = False
        self.node.addIdevice(self.idevice)
        return self.idevice
    def __str__(self):
        return self.relpath
    def __repr__(self):
        return self.relpath
    def addLink(self,link):
        self.links.append(link)
    def addPLink(self,link):
        self.plinks.append(link)
    def addRLink(self,link):
        self.rlinks.add(link)

class Resources:
    cancel = False
    @classmethod
    def cancelImport(cls):
        cls.cancel = True
        #TODO Deshacer todo lo que se lleve hecho
    def __init__(self, baseurl, node, client=None):
        self.baseurl = baseurl.decode(sys.getfilesystemencoding())
        self.node = node
        self.client = client
        self.numdirs = 0
        resources = {}
        resources['mimes'] = {}
        resources['urls'] = {}
        
        url = Url(self.baseurl, self.baseurl)
        url.createNode(node, _('Contents of directory'))
        resources['urls'][url.relpath] = url
        try:
            for root, dirs, files in self._safewalk(self.baseurl):
                if self.cancel:
                    return
                self.numdirs += 1
        except UnicodeDecodeError:
            raise
        i = 1
        for root, dirs, files in self._safewalk(self.baseurl):
            html = u""
            idevice = None
            if self.client:
                self.client.call('eXe.app.getController("Toolbar").updateImportProgressWindow',_(u'Analizing directory %d of %d: %s') % (i, self.numdirs,root.encode(sys.getfilesystemencoding())))
            for dir in dirs:
                if self.cancel:
                    return
                path = root + os.path.sep + dir
                url = Url(path, self.baseurl)
                url.createNode(resources['urls'][url.parentpath].node)
                resources['urls'][url.relpath] = url
            for file in files:
                if self.cancel:
                    return
                path = root + os.path.sep + file
                url = Url(path, self.baseurl)
                parent = resources['urls'][url.parentpath]
                if not idevice:
                    idevice = parent.createIdevice()
                try:
                    p = Path(path)
                    p.setSalt(str(url))
                    r = Resource(idevice,p)
                except:
                    continue
                url.href = 'resources/%s' % (quote(r.storage