#!/usr/bin/env python
import os, sys
import argparse
import functools

from quickfind.Searcher import Searcher, Ranker, CursesPrinter
import quickfind.Console as Console
from quickfind.source.DirectorySource import DirectorySource, SimpleRanker, formatter
from quickfind.source.CtagsSource import CtagsSource, CtagsRanker, CtagsFormatter
from quickfind.source.Util import rec_dir_up

class Runner(object):
    def __init__(self, args):
        self.rows, self.columns = Console.getDims()
        self.args= args

    def find(self):
        raise NotImplementedError()

    def run(self):
        filename = self.find()
        if filename is not None:
            if self.args.s is not None:
                with file(self.args.s, 'w') as f:
                     f.write(filename)
            else:
                v = os.environ['EDITOR']
                os.execvp(v, [v, filename])      

class DirRun(Runner):

    def find(self):

        git_ignore = self.args.g
        if self.args.fileType == 'all':
            ds = DirectorySource(ignore_directories=False, 
                    ignore_files=False, git_ignore=git_ignore)
        elif self.args.fileType == 'files':
            ds = DirectorySource(ignore_files=False, git_ignore=git_ignore)
        else:
            ds = DirectorySource(ignore_directories=False, git_ignore=git_ignore)

        items = ds.fetch()

        sr = SimpleRanker.new(self.args.w, self.args.p)
        s = Searcher(sr, CursesPrinter(formatter))
        try:
            found = s.run(items)
        except KeyboardInterrupt:
            sys.exit(0)

        if found is not None:
            found = os.path.join(found.dir, found.name)
        return found 

class CtagsRun(Runner):

    def find(self):
        ctagsFile = self.find_ctag_file()
        if ctagsFile is None:
            print "Could not find ctags file"
            sys.exit(1)

        items = CtagsSource(ctagsFile).fetch()
        s = Searcher(CtagsRanker, CursesPrinter(CtagsFormatter(self.columns)))
        try:
            found = s.run(items, self.rows - 3)
        except KeyboardInterrupt:
            sys.exit(0)
        if found is not None:
            return found.file

    def find_ctag_file(self):
        directory = os.getcwd()
        for dir in rec_dir_up(directory):
            path = os.path.join(dir, "tags")
            if os.path.isfile(path):
                return path

        return None

def build_arg_parser():
    parser = argparse.ArgumentParser(description='Quickfind on various archives.')
    parser.add_argument('-c', 
            action="store_true", help='Ctags quickfind')
    parser.add_argument('-s', 
            help='Writes the file to provided file instead of executing it.')
    parser.add_argument('-g', 
            action="store_false", help='Do not filter out files in .gitignore')
    parser.add_argument('-w', 
            action="store_true", help='White space separates multiple queries')
    parser.add_argument('-p', 
            action="store_true", help='Match also on path')

    group = parser.add_mutually_exclusive_group()
    group.add_argument('-d', action="store_const", dest="fileType", const="dirs",
                        help='Directories only.')
    group.add_argument('-a', action="store_const", dest="fileType", const="all",
                        help='Both files and directories.')
    parser.set_defaults(fileType="files")

    return parser.parse_args()

if __name__ == '__main__':
    args = build_arg_parser()
    if args.c:
        runner = CtagsRun(args)
    else:
        runner = DirRun(args)

    runner.run()
