# -*- coding: utf-8 -*-

# Copyright (C) 2005 Maciej Katafiasz
#
# Author: Maciej Katafiasz
#
# This file is part of Purrr programme.
#
# Purrr 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, or (at your
# option) any later version.
#
# Purrr 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 Purrr; see the file COPYING. If not, write to the
# Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.

import re,sys,os
import types
sys.path.append("/tmp/")
import directoriodetrabajo

import gettext  
import gtk.glade
APP="purrr"  
DIR=directoriodetrabajo.libdir+"/po"  
gettext.textdomain(APP)  
gettext.bindtextdomain(APP, DIR)
gtk.glade.textdomain(APP)  
gtk.glade.bindtextdomain(APP, DIR)  
_ = gettext.gettext

class NoTemplateDefinedError:
    pass

class FileRenamer:
    class State:
        pass
    def __init__(self, template):
        self.init(template)
        
    def init(self, template):
        self.template = template
        self.__state = self.State()
        self.__parse_template()

    def valid_counter(self, str):
        return re.match("^[Cc]\d*(,([+-]?\d*))?(,([+-]?\d*))?(,(\d*))?$", str)

    def valid_nameref(self, str):
        return re.match("^[Nn][_!]*(\d*:\d*)?$", str)

    def valid_baseref(self, str):
        return re.match("^[Bb][_!]*(\d*:\d*)?$", str)

    def valid_extref(self, str):
        return re.match("^[Ee][!.]*(\d*:\d*)?$", str)

    def valid_slice(self, str):
        return re.match("^\d*:\d*[_!.-]*$", str)

    def parse_nameref(self, str):
        ret = 'info.old_name'
        m = re.match("^[Nn](?:(?P<replace>_)|(?P<up>!))*(?:(?P<first>\d*):(?P<last>\d*))?$", str)
        if str[0] == 'n':
            ret += '.lower()'
        if m:
            if m.group("replace"):
                ret += '.replace("_", " ")'
            if m.group("up"):
                ret += '.upper()'
            ret += "[%s:%s]" % ((m.group("first") or ""), (m.group("last") or ""))
        return ret 

    def parse_baseref(self, str):
        ret = 'info.base_name'
        m = re.match("^[Bb](?:(?P<replace>_)|(?P<up>!))*(?:(?P<first>\d*):(?P<last>\d*))?$", str)
        if str[0] == 'b':
            ret += '.lower()'
        if m:
            if m.group("replace"):
                ret += '.replace("_", " ")'
            if m.group("up"):
                ret += '.upper()'
            ret += "[%s:%s]" % ((m.group("first") or ""), (m.group("last") or ""))
        return ret 

    def parse_extref(self, str):
        ret = 'info.extension'
        m = re.match("^[Ee](?:(?P<dot>\.)|(?P<up>!))*(?:(?P<first>\d*):(?P<last>\d*))?$", str)
        if m:
            if m.group("dot"):
                ret = '((info.extension and ("." + info.extension)) or "")'
            if str[0] == 'e':
                ret += '.lower()'
            if m.group("up"):
                ret += '.upper()'
            ret += "[%s:%s]" % ((m.group("first") or ""), (m.group("last") or ""))
        return ret 

    def parse_counter(self, str):
        m = re.match("^[Cc](?P<name>\d+)?$", str)
        if m:
            return (m.group('name'), 1, 1, 1, None)
        
        m = re.match("^[Cc](?P<name>\d+)?,(?P<start>[+-]?\d+)?$", str)
        if m:
            return (m.group('name'), 1, 1, int(m.group('start') or 1), None)

        m = re.match("^[Cc](?P<name>\d+)?,(?P<start>[+-]?\d+)?,(?P<step>[+-]?\d+)?$", str)
        if m:
            return (m.group('name'), int(m.group('step') or 1), 1, int(m.group('start') or 1), None)

        m = re.match("^[Cc](?P<name>\d+)?,(?P<start>[+-]?\d+)?,(?P<step>[+-]?\d+)?,(?P<pad>[+-]?\d+)?$", str)
        if m:
            return (m.group('name'),int(m.group('step') or 1), int(m.group('pad') or 1), int(m.group('start') or 1), None)

    def __parse_template(self):
        t = self.template
        last = t.find("[")
        
        init = "def __init__(self):\n"
        code = """
def next_name(self, info):
    name = \"\""""
        fini = ""
        n_counters = 0
        counters = {}
        for chunk in self.chunkify(t):
            if (chunk[1] == "special") and self.valid_counter(chunk[0]):
                cnt = self.parse_counter(chunk[0])
                try:
                    cnt = counters[cnt[0] or n_counters]
                except KeyError:
                    cntname = (cnt[0] or repr(n_counters)).replace("-","_")
                    counters[cnt[0] or n_counters] = cnt
                    init += "    self.C" + cntname  + " = " + repr(cnt[1]) + "\n"

                    fini += "    self.C" + cntname  + " += " + repr(cnt[2])
                    wrap = cnt[4]
                    if wrap != None : #and cnt[1] < wrap:
                        fini += "\n    self.C" + cntname + " = (self.C" + cntname + \
                        " - " + repr(cnt[1]) + ") % " + repr(wrap - cnt[1] + 1) + " + " + \
                        repr(cnt[1])
                    fini +=  "\n"
                    print fini
                code += " + repr(self.C" + (cnt[0] or repr(n_counters)).\
                replace("-","_") + ").zfill(" + repr(cnt[3]) + ")"

                n_counters += 1

            elif (chunk[1] == "special") and self.valid_nameref(chunk[0]):
                code += " + " + self.parse_nameref(chunk[0])

            elif (chunk[1] == "special") and self.valid_baseref(chunk[0]):
                code += " + " + self.parse_baseref(chunk[0])

            elif (chunk[1] == "special") and self.valid_extref(chunk[0]):
                code += " + " + self.parse_extref(chunk[0])

            else:
                if chunk[0]:
                    code += " + \"" + chunk[0].replace("\"","\\\"") + "\""

        # If there are no counters, make sure __init__ is still valid code
        init += "    pass\n"
        code += "\n"
        fini += "    return name\n"

        c = compile(init + code + fini, repr(self), "exec")
        x = {}
        exec c in globals(), self.State.__dict__
        self.__state = self.State()
        self.State.next_name = types.MethodType(self.State.__dict__['next_name'], self.__state)

    def next_name(self, old_name):
        return self.__state.next_name(old_name)

    def chunkify(self, s):
        _("""Parse string, chopped into "plain" and "special" slices.
Slice is special if enclosed in [ and ], unless braces are escaped with \\.
Everything else is plain. Unescaped braces are swallowed""")
        r = ""
        state = "plain"
        escape = False
        for i in s:
            if i == "\\" and not escape:
                escape = True
                continue
            if state == "plain":
                if i == "[" and not escape:
                    state = "special"
                    if r: yield (r, "plain")
                    r = ""
                else:
                    r = r + i
            else:
                if i == "]" and not escape:
                    state = "plain"
                    if r: yield (r, "special")
                    r = ""
                else:
                    r = r + i
            escape = False
        yield (((state == "special" and "[") or "") + r, "plain")
