# -*- coding: ascii -*-

###########################################################################
# clive, video extraction utility
# Copyright (C) 2007-2008 Toni Gundogdu
#
# This file is part of clive.
#
# clive is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# clive 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with clive.  If not, see <http://www.gnu.org/licenses/>.
###########################################################################

## Standard input related classes for reading and parsing

__all__ = ['Console']

from clive.path import ConfigDir 
from clive.opts import Options
from clive.modules import Modules

## The console class for reading and parsing standard input and commands
class Console:

    ## Constructor
    def __init__(self, say):
        self._sys = Modules().getinst('sys')
        self._opts = Options()._opts
        self._say = say
        self._cmds = [
        ('set [var] [value]', 'e.g. set http_proxy http://foo:80', self._onset),
        ('q_ls [index]', 'list index in queue', self._onls),
        ('q_rm [index]', 'remove index from queue', self._onrm),
        ('q_clr','clear queue of all items', self._onclrq),
        ('q_mv [from] [to]', 'move item from index to index', self._onmv),
        ('q_srt', 'sort queue', self._onsortq),
        ('q_rev', 'reverse queue order', self._onrevq),
        ('q_import [filename]', 'read urls from file', self._onreadfile),
        ('q_export [filename] [overwrite]',
            'export queue to file (default: append)', self._onwritefile),
        ('q_paste', 'read from clipboard (xclip)', self._onpaste),
        ('q_recall', 'recall last batch', self._onrecall),
        ('quit', 'quit', self._onquit),
        ('help', 'this help', self._onhelp)]
	
    ## Read input from stdin, ~/.clive/recall or xclip
    def read(self):
        self._urls = []
        pipe = self._sys.stdin
        if self._opts.enable_xclip_paste:
            pipe = self._paste()
        elif self._opts.recall:
            pipe = self._recall()
        while 1:
            ln = pipe.readline()
            if len(ln) == 0: break
            ln = ln.rstrip('\n')
            if len(ln) == 0: continue
            # Parse
            if self._iscmd(ln):
                pass
            elif self._isurl(ln):
                if ln not in self._urls:
                    self._urls.append(ln)
            else:
                self._say('error: unrecognized command (%s), ' \
                'try "help".' % ln)
        return (self._urls)
	
    def _paste(self):
        pipe = self._sys.stdin # Default
        if not self._opts.xclip:
            self._say('warn: --xclip unused, cannot ' +
                'read from clipboard')
        else:
            cmd = self._opts.xclip + ' 2>/dev/null'
            subprocess = Modules().getinst('subprocess')
            pipe = subprocess.Popen(cmd, shell=1,
                stdout=subprocess.PIPE).stdout
        return pipe

    def _recall(self):
        pipe = self._sys.stdin # Default
        try:
            StringIO = Modules().getinst('StringIO')
            pipe = StringIO(open(ConfigDir().recallfile(), 'r').read())
        except IOError, err:
            raise SystemExit('error: no recall data')
        return pipe

    def _setvar(self, var, val):
        try:
            getattr(self._opts, var)
            setattr(self._opts, var, val)
            self._say('"%s" is now "%s".' % (var, val))
        except AttributeError:
            self._say('error: invalid variable (%s).' % var)
	
    def _getvar(self, var):
        try:
            a = getattr(self._opts, var)
            self._say('"%s" is "%s"' % (var, a))
        except AttributeError:
            self._say('error: invalid variable (%s).' % var)
	
    def _listvars(self):
        self._say('available variables:')
        for opt in self._opts.__dict__:
            if not opt.startswith('_'):
                self._say('  "%s" (%s)' % (opt, getattr(self._opts, opt)))

    def _iscmd(self, ln):
        try:
            c = ln.split()[0]
        except IndexError:
            c = ln
        for (cmd, desc, func) in self._cmds:
            if c.lower() == cmd.split()[0]:
                func(ln)
                return 1
        return 0
	
    def _isurl(self, ln):
        if len(ln.split()) == 1:
            if '.' in ln: return 1
        return 0
	
    def _onset(self, ln):
        s = ln.split()
        if len(s) == 3:
            self._setvar(s[1], s[2])
        elif len(s) == 2:
            self._getvar(s[1])
        else:
            self._listvars()
	
    def _onls(self, ln):
        s = ln.split()
        if len(s) == 2:
            try:
                i = int(s[1])
                self._say('%d: %s' % (i, self._urls[i]))
            except IndexError:
                self._say('error: invalid index.')
        else:
            self._say('queue:')
            for (index, url) in enumerate(self._urls):
                self._say('%d: %s' % (index, url))
	
    def _onrm(self, ln):
        s = ln.split()
        if len(s) == 2:
            try:
                i = int(s[1])
                del self._urls[i]
            except IndexError:
                self._say('error: invalid index.')
        else:
            self._say('error: specify index.')
	
    def _onclrq(self, ln):
        self._urls = []
        self._say('cleared.')
	
    def _onmv(self, ln):
        s = ln.split()
        if len(s) == 3:
            try:
                index = int(s[1])
                to = int(s[2])
                self._urls.insert(to, self._urls.pop(index))
                self._say('moved %d to %d.' % (index, to))
            except IndexError:
                self._say('error: invalid index.')
        else:
            self._say('error: specify both "to" and "from" indices.')
	
    def _onsortq(self, ln):
        self._urls.sort()
        self._say('sorted.')
	
    def _onrevq(self, ln):
        self._urls.reverse()
        self._say('reversed.')

    def _readfile(self, filename):
        try:
            f = open(filename, 'r')
            added = 0
            for ln in f:
                if len(ln) == 0: break
                ln = ln.rstrip('\n')
                if len(ln) == 0: continue
                if self._isurl(ln):
                    if ln not in self._urls:
                        self._urls.append(ln)
                        added += 1
            self._say('added %d new urls.' % added)
            f.close()
        except IOError, err:
            self._say('error: %s' % repr(err))

    def _onreadfile(self, ln):
        s = ln.split()
        if len(s) == 2:
            self._readfile(s[1])
        else:
            self._say('error: filename not specified.')
	
    def _onwritefile(self, ln):
        s = ln.split()
        if len(s) >= 2:
            try:
                mode = 'a'
                if len(s) == 3:
                    if s[2] == 'overwrite': m = 'w'
                f = open(s[1], mode) 
                for url in self._urls:
                    f.write(url + '\n')
                self._say('%d urls written.' % len(self._urls))
                f.close()
            except IOError, err:
                self._say('error: %s' % repr(err))
        else:
            self._say('error: filename not specified.')
	
    def _onpaste(self, ln):
        pipe = self._paste()
        if pipe == self._sys.stdin: return
        added = 0
        while 1:
            ln = pipe.readline()
            if len(ln) == 0: break
            ln = ln.rstrip('\n')
            if len(ln) == 0: continue
            if self._isurl(ln):
                if ln not in self._urls:
                    self._urls.append(ln)
                    added += 1
        self._say('added %d new urls.' % added)

    def _onrecall(self, ln):
        self._readfile(ConfigDir().recallfile())

    def _onquit(self, ln):
        raise SystemExit

    def _onhelp(self, ln):
        self._say('commands:')
        for (cmd, desc, func) in self._cmds:
            self._say('  %s .. %s' % (cmd.ljust(32), desc))
        self._say('NOTE: input that contains "." will be added to queue')
