# -*- coding: utf-8 -*-
#
# Copyright (C) 2005 Edgewall Software
# Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de>
# Copyright (C) 2005 Matthew Good <trac@matt-good.net>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Christopher Lenz <cmlenz@gmx.de>
#         Matthew Good <trac@matt-good.net>

import locale
import os
import sys
import urllib
import re

from trac.core import *
from trac.env import * 
from trac.perm import IPermissionRequestor, PermissionCache, PermissionSystem, PermissionError
from trac.util import get_last_traceback
from trac.util.text import to_unicode
from trac.util.html import Markup
from trac.util.datefmt import format_datetime, http_date, localtz, timezone
from trac.web.api import *
from trac.web.api import IRequestHandler, HTTPBadRequest
from trac.web.chrome import *
from trac.web.href import Href
from genshi.filters.transform import Transformer
from genshi.template import MarkupTemplate
from trac.wiki.web_ui import WikiModule
from trac.web.main import populate_hdf, open_environment, get_environments
from trac.web.main import RequestDispatcher
from trac.web.session import Session
from trac.web.chrome import add_stylesheet, add_script
from trac.util.translation import _
try:
    from trac.util.translation import _tbl
    _tbl.update({
        'Available Project':'利用可能なプロジェクト',
        'total':'合計',
        'All Project Roadmap':'全てのプロジェクトのロードマップ',
        'All Project Timeline':'全てのプロジェクトのタイムライン',
        'All Project Source':'全てのプロジェクトのソース',
        'All Project Tickets':'全てのプロジェクトのチケット',
        'Show My Tickets':'自分のチケット',
        'Tickets Reported by Me':'自分が報告したチケット',
    })
except:
    {}

# Environment cache for multithreaded front-ends:
try:
    import threading
except ImportError:
    import dummy_threading as threading

env_cache = {}
env_cache_lock = threading.Lock()

def get_project_list(environ, href, authname='anonymous', require_auth=True, permission='PROJECT_ACCESS'):
    projects = []
    for env_name, env_path in get_environments(environ).items():
        try:
            # env is 
            #  <class 'trac.env.Environment'>
            env = __open_environment(env_path,
                                    run_once=environ['wsgi.run_once'])

            if require_auth:
                if not is_authorised(authname, PermissionCache(env, authname), env, list_permission=permission):
                    continue

            env.path = env_path
            
            if env_name == 'all':
                env.isall = True
                continue

            env.isall = False
            proj = {
                'name': env.project_name,
                'description': env.project_description,
                'href': href(env_name),
                'env_name': env_name,
                'env':env
            }
            is_target = env.config.get('tram', 'include_project_list') or 'true';
            if is_target == 'true':
                projects.append(proj)
        except Exception, e:
            #proj = {'name': env_name, 'description': to_unicode(e)}
            debug(to_unicode(e))
            pass

    projects.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower()))
    return projects

def get_allenv(environ, req):

    for env_name, env_path in get_environments(environ).items():
        try:
            env = __open_environment(env_path,
                                    run_once=environ['wsgi.run_once'])

            if env_name == 'all':
                env.isall = True
                if not env.abs_href.base:
                    env._abs_href = req.abs_href
                return env
        except Exception, e:
            continue

    projects = get_project_list(environ, get_parent_href(req), require_auth=False)
    if len(projects) > 0:
        return projects[0]['env']
    return None

def is_authorised(authname, perms, env, permission=None, list_permission='PROJECT_ACCESS'):
    if not authname:
        authname = 'anonymous'
        perms = PermissionCache(env, authname)

    if not perms.has_permission(list_permission):
        return False

    if permission:
        return perms.has_permission(permission)

    return True

def update_request(req, chrome):
    # Setup request callbacks for lazily-evaluated properties
    req.callbacks.update({
        'authname': dummy_func,
        'chrome': chrome.prepare_request,
#        'hdf': dummy_func,
#        'perm': dummy_func,
#        'session': dummy_func,
        'tz': dummy_func,
        'form_token': dummy_func
    })
                
def dummy_func(req):
    return None

def prepare_request(req, environ):

    href = Href(req.href.all())
    anenv = get_allenv(environ, req)
    req.href = href
    req.abs_href = Href(req.abs_href.all())
    chrome = Chrome(anenv)

    update_request(req, chrome)

    # auth must be checked before this method runs, we are not a component yet
    req.perm = PermissionCache(anenv, req.authname)
    req.session = Session(anenv, req)

    loadpaths = chrome.get_all_templates_dirs();
    loadpaths.insert(0, os.path.dirname(__file__) + "/templates/")

    req.hdf = {}
    populate_hdf(req.hdf, anenv, req)

    # after populate, add styles and scripts
    path_info = environ.get('PATH_INFO', '').lstrip('/').split('/')
    env_name = path_info.pop(0)
    if len(path_info) == 0 or (len(path_info) == 1 and path_info[0] == ''):
        add_stylesheet(req, "tram/css/project-list.css")
    elif path_info[0] == 'roadmap':
        add_stylesheet(req, 'common/css/roadmap.css')
    elif path_info[0] == 'timeline':
        add_stylesheet(req, 'common/css/timeline.css')
    elif path_info[0] == 'query':
        add_stylesheet(req, 'common/css/report.css')
    elif path_info[0] == 'browser':
        add_stylesheet(req, 'common/css/browser.css')
    elif path_info[0] == 'search':
        add_stylesheet(req, 'common/css/search.css')
        add_stylesheet(req, 'tram/css/whole-search.css')
        add_script(req, 'tram/js/jquery-1.1.2.pack.js')
        add_script(req, 'tram/js/jquery.compat-1.0.js')
        add_script(req, 'tram/js/trac_ws.js')
    
    chrome.populate_hdf(req)

    req.hdf['tram.version'] = "0.3"
    req.hdf["tram_htdocs_location"] = req.hdf["htdocs_location"].replace("common", "tram")

    # We want to display the guide whether we are using an "all" env or not
    # As the elements are already ordered we hijac the about element and reassign it below
    req.hdf['chrome.nav.metanav.about'] = Markup('<a href="' + href.wiki('TracGuide') + '">Help/Guide</a>')
    req.hdf['chrome.nav.metanav.help'] = Markup('<a href="' + href.about() + '">About Trac</a>')

    # Here we are adding some links to plugins as they seem not to be loading now...
    if (anenv.isall):
        req.hdf['chrome.nav.mainnav.wiki'] = Markup('<a href="' + href.wiki() + '">Wiki</a>')

    req.hdf['chrome.nav.mainnav.timeline'] = Markup('<a href="' + href.timeline() + '">' + _('Timeline') + '</a>')
    req.hdf['chrome.nav.mainnav.roadmap'] = Markup('<a href="' + href.roadmap() + '">' + _('Roadmap') + '</a>')
    req.hdf['chrome.nav.mainnav.browser'] = Markup('<a href="' + href.browser('/') + '">' + _('Browse Source') + '</a>')
    req.hdf['chrome.nav.mainnav.tickets'] = Markup('<a href="' + href.query() + '">' + _('View Tickets') + '</a>')
    req.hdf['chrome.nav.mainnav.search'] = Markup('<a href="' + href.search() + '">' + _('Search') + '</a>')
    return chrome

def __open_environment(env_path, run_once=False):
    if run_once:
        return open_environment(env_path)

    global env_cache, env_cache_lock
    env = None
    env_cache_lock.acquire()
    try:
        if not env_path in env_cache:
            env_cache[env_path] = open_environment(env_path)
        env = env_cache[env_path]
    finally:
        env_cache_lock.release()

    # Re-parse the configuration file if it changed since the last the time it
    # was parsed
    env.config.parse_if_needed()

    return env

def get_parent_href(req):
    uri = re.sub(r'/[^/]+/?\Z', '', req.href())
    return Href(uri or '/')

def debug(message):
    import inspect
    import os.path
    frame = inspect.currentframe().f_back
    lineno = frame.f_lineno
    filename = os.path.basename(frame.f_code.co_filename)
    text = '%s:%d %s\n' % (filename, lineno, message)
    sys.stderr.write(text)
    sys.stderr.flush()
