# -*- 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

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.clearsilver import HDFWrapper
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 _

# 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

            projectHref = Href(href(env_name))
            env._href = projectHref
            env._abs_href = projectHref
            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
            }
            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, href):

    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
                return env
        except Exception, e:
            continue
    plist = get_project_list(environ, href)
    return plist[0]['env']

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.href)
    anenv._href = href
    req.href = href
    anenv._abs_href = req.abs_href
    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 = HDFWrapper(loadpaths)
    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 debug(message):
    import inspect
    sys.stderr.write(str(inspect.currentframe().f_back.f_lineno) + ":" + str(message) + "\n")
