#!/usr/bin/env python
#
# Copyright (C) 2009 Samsung Electronics.
#
# This file is part of Editje.
#
# Editje is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Editje 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with Editje. If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import re
from optparse import OptionParser
import errno
import logging

import elementary
import edje

from editje.sysconfig import VERSION
from editje.editje import Editje
import editje.swapfile as swapfile
from editje.popup_win import PopupWindow


logger = logging.getLogger('editje')
logger.setLevel(logging.DEBUG)
_handler = logging.FileHandler("/tmp/editje_log", mode='w')
_formatter = logging.Formatter("%(asctime)s %(levelname)s "
                               "%(filename)s:%(lineno)d %(funcName)s "
                               "%(message)s")
_handler.setFormatter(_formatter)
logger.addHandler(_handler)


vtext = "editje " + str(VERSION)
usage = "usage: %prog [FILE [GROUP]]\n" + \
    "   or: %prog -s [-i IN_PORT] FILE GROUP"

parser = OptionParser(usage=usage, version=vtext)
parser.add_option(
    "-s", "--slave-mode", action="store_true", dest="slave", default=False,
    help="open editor in slave mode")
parser.add_option(
    "-i", "--in-port", dest="in_port", type="int", default=8000,
    help="listening port number, for slave mode (default is 8000)")

file_re = re.compile(r"(.*\.ed[cj])$")
group_re = re.compile(r"([a-zA-Z0-9_]+)$")


def file_and_group_parse(file_, grp):
    r = file_re.match(file_)
    if not r:
        #FIXME: do we really want to barf for non ".*\.ed[cj]"
        #file names? Maybe to document it in the usage string,
        #then
        parser.error("wrong format for FILE argument")

    f = r.group(0)

    if not grp:
        return [f, ""]

    r = group_re.match(grp)
    if not r:
        parser.error("wrong format for GROUP argument")

    return [f, r.group(0)]

def _open_force_ok_cb(sf, filepath=None, group=None, slave_mode=False, in_port=None, mode=0, pop=None):
    logger.debug("Open editje forced: file='%s' group='%s' force_mode=%d "
		 "slave_mode=%s in_port=%s", filepath, group, mode,
		 slave_mode, in_port)
    editje = Editje(sf, slave_mode=slave_mode, in_port=in_port)

    if group and group in edje.file_collection_list(sf.workfile):
        editje.group = group

    if pop:
        pop.hide()
    editje.show()
    if pop:
        pop.delete()

def _open_force_cb(bt, data):
    pop, mode, filepath, group, slave_mode, in_port = data
    logger.debug("Open file (force): file='%s' group='%s' force_mode=%d"
                 " slave_mode=%s in_port=%s", filepath, group, mode, slave_mode,
                 in_port)
    swapfile.open(filepath, _open_force_ok_cb, _open_err_cb, mode=mode, group=group,
                  slave_mode=slave_mode, in_port=in_port, pop=pop)

def _open_abort_cb(bt, pop):
    pop.hide()
    pop.delete()


def _open_ok_cb(sf, filepath=None, group=None, slave_mode=False, in_port=None):
    logger.debug("Open editje: file='%s' group='%s' slave_mode=%s in_port=%s",
                  filepath, group, slave_mode, in_port)
    editje = Editje(sf, slave_mode=slave_mode, in_port=in_port)

    if group and group in edje.file_collection_list(sf.workfile):
        editje.group = group

    editje.show()


def _open_err_cb(e, filepath=None, group=None, slave_mode=None, in_port=None):

    logger.error("Open file: file='%s' group='%s' slave_mode=%s "
            "in_port=%s : %s", filepath, group, slave_mode, in_port, e)

    if slave_mode:
        raise RuntimeError(str(e))

    if isinstance(e, IOError) and e.errno == errno.EEXIST:
        pop = PopupWindow()
        pop.title = "Editje - Swap file already exists"

        lb = elementary.Label(pop)
        lb.text_set(
                "Swap file to " + filepath + " already exists.<br>" +
                "Another program may be editing the same file<br>" +
                "or an edition session for this file crashed.")
        pop.pack_end(lb)
        lb.show()

        pop.action_add("Ignore Swap", _open_force_cb,
                       data=(pop, swapfile.REPLACE, filepath, group,
                             slave_mode, in_port))
        pop.action_add("Recover", _open_force_cb,
                       data=(pop, swapfile.RESTORE, filepath, group,
                             slave_mode, in_port))
        pop.action_add("Abort", _open_abort_cb, data=pop)

        pop.show()
    elif isinstance(e, swapfile.CompileError):
        pop = PopupWindow()
        pop.title = "Editje - Compiler Error"

        lb = elementary.Label(pop)
        lb.text_set("Compile Error: " + filepath + "<br>" + e.message)
        pop.pack_end(lb)
        lb.show()

        pop.action_add("OK", _open_abort_cb, data=pop)

        pop.show()
    else:
        pop = PopupWindow()
        pop.title = "Editje - File Error"

        lb = elementary.Label(pop)
        lb.text_set("Error with file: " + filepath + "<br>" + str(e))
        pop.pack_end(lb)
        lb.show()

        pop.action_add("OK", _open_abort_cb, data=pop)

        pop.show()


def open_editje(filename, group, slave_mode=False, in_port=None):
        mode = None
        if slave_mode:
            mode = swapfile.REPLACE
        if not slave_mode and not filename:
            logger.debug("Open new file: group='%s' slave_mode=%s in_port=%s",
                         group, slave_mode, in_port)
            swapfile.open_new(_open_ok_cb, _open_err_cb, group=group,
                              slave_mode=slave_mode, in_port=in_port)
        else:
            filepath = os.path.realpath(filename)
            logger.debug("Open file: file='%s' group='%s' slave_mode=%s "
                         "in_port=%s", filepath, group, slave_mode, in_port)
            swapfile.open(filepath, _open_ok_cb,
                          _open_err_cb, mode=mode, group=group,
                          slave_mode=slave_mode, in_port=in_port)


if __name__ == "__main__":
    logger.info("Editje " + VERSION)
    elementary.init()
    elementary.finger_size_set(15)
    elementary.policy_set(elementary.ELM_POLICY_QUIT,
                          elementary.ELM_POLICY_QUIT_LAST_WINDOW_CLOSED)

    options, args = parser.parse_args()
    slave_mode = options.slave

    args_dict = {}

    if slave_mode:
        if not args:
            parser.error("incorrect number of arguments")

        if len(args) != 2:
            parser.error("incorrect number of arguments")

        file_, group = file_and_group_parse(args[0], args[1])

        args_list = [file_, group, slave_mode]
        args_dict = {"in_port": options.in_port}
    elif not args:
        args_list = ["", "main"]
    else:
        if len(args) == 1:
            file_, group = file_and_group_parse(args[0], "")
        elif len(args) == 2:
            file_, group = file_and_group_parse(args[0], args[1])
        else:
            parser.error("incorrect number of arguments")

        args_list = [file_, group]

    try:
        open_editje(*args_list, **args_dict)
    except SystemExit, e:
        elementary.shutdown()
        sys.exit(str(e))

    elementary.run()
    elementary.shutdown()
