#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# PyKota : Print Quotas for CUPS
#
# (c) 2003-2009 Jerome Alet <alet@librelogiciel.com>
# This program 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.
#
# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
# $Id$
#
#

"""An On Screen Display (OSD) monitor for PyKota's end users."""

import sys
import os
import pwd
import time

try :
    import pyosd
except ImportError :
    sys.stderr.write("Sorry ! You need both xosd and the Python OSD library (pyosd) for this software to work.\n")
    sys.exit(-1)

import pykota.appinit
from pykota.utils import run, loginvalidparam
from pykota.commandline import PyKotaOptionParser
from pykota.errors import PyKotaToolError, PyKotaCommandLineError
from pykota.tool import PyKotaTool

class PyKOSD(PyKotaTool) :
    """A class for an On Screen Display print quota monitor."""
    def main(self, args, options) :
        """Main function starts here."""
        savecolor = options.color
        loop = options.loop
        username = pwd.getpwuid(os.getuid())[0]
        while True :
            color = savecolor
            user = self.storage.getUserFromBackend(username) # don't use cache
            if not user.Exists :
                raise PyKotaCommandLineError, _("You %(username)s don't have a PyKota printing account. Please contact your administrator.") % locals()
            if user.LimitBy == "quota" :
                printers = self.storage.getMatchingPrinters("*")
                upquotas = [ self.storage.getUserPQuotaFromBackend(user, p) for p in printers ] # don't use cache
                nblines = len(upquotas)
                display = pyosd.osd(font=options.font,
                                    colour=color,
                                    timeout=options.duration,
                                    shadow=2,
                                    lines=nblines)
                for line in range(nblines) :
                    upq = upquotas[line]
                    if upq.HardLimit is None :
                        if upq.SoftLimit is None :
                            percent = "%i" % upq.PageCounter
                        else :
                            percent = "%i%%" % min((upq.PageCounter * 100) / upq.SoftLimit, 100)
                    else :
                        percent = "%i%%" % min((upq.PageCounter * 100) / upq.HardLimit, 100)
                    printername = upq.Printer.Name
                    msg = _("Pages used on %(printername)s : %(percent)s") % locals()
                    display.display(msg.encode(self.charset, "replace"),
                                    type=pyosd.TYPE_STRING,
                                    line=line)
            elif user.LimitBy == "balance" :
                if user.AccountBalance <= self.config.getBalanceZero() :
                    color = "#FF0000"
                display = pyosd.osd(font=options.font,
                                    colour=color,
                                    timeout=options.duration,
                                    shadow=2)
                balance = user.AccountBalance
                msg = _("PyKota Units left : %(balance).2f") % locals()
                display.display(msg.encode(self.charset, "replace"),
                                type=pyosd.TYPE_STRING)
            elif user.LimitBy == "noprint" :
                display = pyosd.osd(font=options.font,
                                    colour="#FF0000",
                                    timeout=options.duration,
                                    shadow=2)
                msg = _("Printing denied.")
                display.display(msg.encode(self.charset, "replace"),
                                type=pyosd.TYPE_STRING)
            elif user.LimitBy == "noquota" :
                display = pyosd.osd(font=options.font,
                                    colour=savecolor,
                                    timeout=options.duration,
                                    shadow=2)
                msg = _("Printing not limited.")
                display.display(msg.encode(self.charset, "replace"),
                                type=pyosd.TYPE_STRING)
            elif user.LimitBy == "nochange" :
                display = pyosd.osd(font=options.font,
                                    colour=savecolor,
                                    timeout=options.duration,
                                    shadow=2)
                msg = _("Printing not limited, no accounting.")
                display.display(msg.encode(self.charset, "replace"),
                                type=pyosd.TYPE_STRING)
            else :
                limitby = repr(user.LimitBy)
                raise PyKotaToolError, "Incorrect limitation factor %(limitby)s for user %(username)s" % locals()

            time.sleep(options.duration + 1)
            if loop :
                loop -= 1
                if not loop :
                    break
            time.sleep(options.sleep)

        return 0

if __name__ == "__main__" :
    def checkandset_positiveint(option, opt, value, optionparser) :
        """Checks and sets positive integer values."""
        if value < 0 :
            loginvalidparam(opt, value, option.default)
            setattr(optionparser.values, option.dest, option.default)
        else :
            setattr(optionparser.values, option.dest, value)

    def checkandset_color(option, opt, value, optionparser) :
        """Checks and sets the color value."""
        if not value.startswith("#") :
            value = "#%s" % value
        try :
            int(value[1:], 16)
        except (ValueError, TypeError) :
            error = True
        else :
            error = False
        if (len(value) != 7) or error :
            loginvalidparam(opt, value, option.default)
            setattr(optionparser.values, option.dest, option.default)
        else :
            setattr(optionparser.values, option.dest, value)

    parser = PyKotaOptionParser(description=_("An On Screen Display (OSD) monitor for PyKota's end users."))
    parser.add_option("-c", "--color", "--colour",
                            type="string",
                            action="callback",
                            callback=checkandset_color,
                            dest="color",
                            default="#00FF00",
                            help=_("Set the color that will be used for display, as an hexadecimal triplet. For example #FF0000 is 100% red. The default is 100% green (%default)."))
    parser.add_option("-d", "--duration",
                            type="int",
                            action="callback",
                            callback=checkandset_positiveint,
                            dest="duration",
                            default=3,
                            help=_("Set the time in seconds during which the message will be displayed. Defaults to %default seconds."))
    parser.add_option("-f", "--font",
                            dest="font",
                            default=pyosd.default_font,
                            help=_("Set the font to use. Defaults to %default."))
    parser.add_option("-l", "--loop",
                            type="int",
                            action="callback",
                            callback=checkandset_positiveint,
                            dest="loop",
                            default=0,
                            help=_("Set the number of times the info will be displayed. Defaults to %default, which means loop forever."))
    parser.add_option("-s", "--sleep",
                            type="int",
                            action="callback",
                            callback=checkandset_positiveint,
                            dest="sleep",
                            default=180,
                            help=_("Set the sleeping time in seconds between two refreshes. Defaults to %default seconds."))

    parser.add_example('-s 60 --loop 5',
                       _("This would tell pykosd to display the current user's status for 3 seconds (the default) every 60 seconds, and exit after 5 iterations."))

    run(parser, PyKOSD)
