#!/usr/bin/env python
#
# KeepNote - note-taking and organization
# Matt Rasmussen 2008
#


# python imports
import sys, os, time, optparse, exceptions, traceback
from os.path import basename, dirname, realpath, join, isdir

# pygtk imports
import pygtk
pygtk.require('2.0')
import gtk
import gtk.gdk
import gobject


#=============================================================================
# KeepNote import

"""
Three ways to run KeepNote

bin_path = os.path.dirname(sys.argv[0])

(1) directly from source dir
    
    pkgdir = bin_path + "../keepnote"
    basedir = pkgdir
    sys.path.append(pkgdir)

    src/bin/keepnote
    src/keepnote/__init__.py
    src/keepnote/images
    src/keepnote/rc

(2) from installation location by setup.py 

    pkgdir = keepnote.get_basedir()
    basedir = pkgdir

    prefix/bin/keepnote
    prefix/lib/python-XXX/site-packages/keepnote/__init__.py
    prefix/lib/python-XXX/site-packages/keepnote/images
    prefix/lib/python-XXX/site-packages/keepnote/rc
    

(3) windows py2exe dir

    pkgdir = bin_path
    basedir = bin_path

    dir/keepnote.exe
    dir/library.zip
    dir/images
    dir/rc

"""

try:
    # try to import from python path first
    import keepnote
    
    # sucessful import, therefore we are running with (2) or (3)
    
    # attempt to use basedir for (2)
    basedir = keepnote.get_basedir()
    
    if not isdir(join(basedir, "images")):
        # we must be running (3)
        basedir = dirname(realpath(sys.argv[0]))
    
except ImportError:
    # try to infer keepnote lib path from program path
    pkgdir = dirname(dirname(realpath(sys.argv[0])))
    sys.path.append(pkgdir)
    import keepnote
    
    # if this works we know we are running from src_path (1)
    basedir = keepnote.get_basedir()


# keepnote imports
import keepnote.gui.main_window
from keepnote.commands import get_command_executor
from keepnote.teefile import TeeFileStream

#=============================================================================
# options

o = optparse.OptionParser(usage=
                "%prog [options] [NOTEBOOK]")
o.set_defaults(default_notebook=True)
o.add_option("", "--show-errors", dest="show_errors",
             action="store_true",
             help="show errors on console")
o.add_option("--no-show-errors", dest="show_errors",
             action="store_false",
             help="do not show errors on console")
o.add_option("--no-default", dest="default_notebook",
             action="store_false",
             help="do not open default notebook")
o.add_option("--listen", dest="listen",
             action="store_true",
             help="listen for commands")
o.add_option("--focus", dest="focus",
             action="store_true",
             help="unminimize and focus an existing window")


#=============================================================================

def start_error_log(show_errors):
    """Starts KeepNote error log"""

    keepnote.init_error_log()

    errorlog = open(keepnote.get_user_error_log(), "a")
    if show_errors:
        sys.stderr = TeeFileStream([sys.stderr, errorlog],
                                   autoflush=True)
    else:
        sys.stderr = errorlog
    

    sys.stderr.write("==============================================\n"
                     "%s %s: %s\n" % (keepnote.PROGRAM_NAME,
                                      keepnote.PROGRAM_VERSION_TEXT,
                                      time.asctime()))



def setup_threading():
    """Initialize threading environment"""
    
    if keepnote.get_platform() == "windows":
        # HACK: keep gui thread active
        def sleeper():
            time.sleep(.001)
            return True # repeat timer
        gobject.timeout_add(400, sleeper)

    else:
        gtk.gdk.threads_init()


def parse_argv(argv):
    """Parse arguments"""

    # set default arguments
    options = o.get_default_values()    
    if keepnote.get_platform() == "windows":        
        options.show_errors = False
    else:
        options.show_errors = True

    # parse args and process
    (options, args) = o.parse_args(argv[1:], options)
    return options, args


def execute_command(app, argv):
    """Execute commands given on command line"""
    
    options, args = parse_argv(argv)
    
    if options.focus:
        if app.window:
            app.window.restore_window()


def contains_command(options, args):
    """Returns True if options contains a command"""
    return options.focus


def main(argv):
    """Main execution"""

    options, args = parse_argv(argv)

    # setup command executor
    if options.listen:
        # start a new listening process
        main_proc, cmd_exec = get_command_executor(True, execute_command)
        if not main_proc:
            # quit, already listening
            print >>sys.stderr, "Cannot listen application already running"
            sys.exit(1)

    elif contains_command(options, args):
        # process command
        main_proc, cmd_exec = get_command_executor(True, execute_command)

    else:
        # create trivial command executor 
        main_proc, cmd_exec = get_command_executor(False, execute_command)
    

    if main_proc:
        # initiate main process

        # setup threading environment
        setup_threading()

        # init preference dir
        if not os.path.exists(keepnote.get_user_pref_dir()):
            keepnote.init_user_pref_dir()

        # start error log
        start_error_log(options.show_errors)

        # read preferences
        app = keepnote.KeepNote(basedir)
        cmd_exec.set_app(app)

        

        # start KeepNote
        if len(args) > 0:
            # open specified notebook
            app.open_notebook(args[0].rstrip("/"))

        elif options.default_notebook and app.pref.default_notebook != "":
            # open default notebook
            app.open_notebook(app.pref.default_notebook)

        else:
            app.show_main_window()

        gtk.main()
        
    else:
        # this is a command process, send command to main process
        cmd_exec.execute(argv)


try:
    main(sys.argv)
    
except exceptions.SystemExit, e:
    # sys.exit() was called
    pass

except Exception, e:
    traceback.print_exc()
    
    # flush final errors
    sys.stderr.flush()
    
