#!/usr/bin/python

# Copyright (C) 2008 Valmantas Paliksa <walmis at balticum-tv dot lt>
#
# Licensed under the GNU General Public License Version 3
#
# 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/>.
# 

import gtk
import datetime
import gettext
import time
from gtraffic.Gconf import Gconf


ui = """
<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkDialog" id="dialog">
    <property name="border_width">5</property>
    <property name="title" translatable="yes">Traffic statistics (v1.01)</property>
    <property name="resizable">False</property>
    <property name="window_position">center</property>
    <property name="icon_name">applications-internet</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <child internal-child="vbox">
      <object class="GtkVBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child>
          <object class="GtkVBox" id="vbox1">
            <property name="visible">True</property>
            <property name="orientation">vertical</property>
            <property name="spacing">11</property>
            <child>
              <object class="GtkHBox" id="hbox1">
                <property name="visible">True</property>
                <child>
                  <object class="GtkAlignment" id="alignment1">
                    <property name="visible">True</property>
                    <property name="yalign">1</property>
                    <property name="xscale">0</property>
                    <property name="yscale">0</property>
                    <child>
                      <object class="GtkToggleButton" id="tb_edit">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">True</property>
                        <property name="image">image1</property>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkVBox" id="vbox2">
                    <property name="visible">True</property>
                    <property name="orientation">vertical</property>
                    <child>
                      <object class="GtkLabel" id="label1">
                        <property name="visible">True</property>
                        <property name="label" translatable="yes">&lt;b&gt;Downloaded:&lt;/b&gt;</property>
                        <property name="use_markup">True</property>
                      </object>
                      <packing>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkEntry" id="e_dl">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="editable">False</property>
                        <property name="invisible_char">&#x25CF;</property>
                        <property name="xalign">0.5</property>
                        <property name="primary_icon_stock">gtk-go-down</property>
                      </object>
                      <packing>
                        <property name="position">1</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="padding">2</property>
                    <property name="position">1</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkVBox" id="vbox3">
                    <property name="visible">True</property>
                    <property name="orientation">vertical</property>
                    <child>
                      <object class="GtkLabel" id="label2">
                        <property name="visible">True</property>
                        <property name="label" translatable="yes">&lt;b&gt;Uploaded:&lt;/b&gt;</property>
                        <property name="use_markup">True</property>
                      </object>
                      <packing>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkEntry" id="e_ul">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="editable">False</property>
                        <property name="invisible_char">&#x25CF;</property>
                        <property name="xalign">0.5</property>
                        <property name="primary_icon_stock">gtk-go-up</property>
                      </object>
                      <packing>
                        <property name="position">1</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="padding">2</property>
                    <property name="position">2</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkVBox" id="vbox4">
                <property name="visible">True</property>
                <property name="orientation">vertical</property>
                <child>
                  <object class="GtkLabel" id="label3">
                    <property name="visible">True</property>
                    <property name="label" translatable="yes">&lt;b&gt;Total:&lt;/b&gt;</property>
                    <property name="use_markup">True</property>
                  </object>
                  <packing>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkEntry" id="e_total">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="editable">False</property>
                    <property name="invisible_char">&#x25CF;</property>
                    <property name="xalign">0.5</property>
                    <property name="caps_lock_warning">False</property>
                    <property name="primary_icon_stock">gtk-info</property>
                  </object>
                  <packing>
                    <property name="position">1</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkTable" id="table1">
                <property name="visible">True</property>
                <property name="n_rows">2</property>
                <property name="n_columns">2</property>
                <property name="column_spacing">11</property>
                <property name="row_spacing">6</property>
                <child>
                  <object class="GtkLabel" id="label4">
                    <property name="visible">True</property>
                    <property name="xalign">0</property>
                    <property name="label" translatable="yes">&lt;b&gt;Log started:&lt;/b&gt;</property>
                    <property name="use_markup">True</property>
                  </object>
                  <packing>
                    <property name="x_options">GTK_FILL</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label5">
                    <property name="visible">True</property>
                    <property name="xalign">0</property>
                    <property name="label" translatable="yes">&lt;b&gt;Log duration:&lt;/b&gt;</property>
                    <property name="use_markup">True</property>
                  </object>
                  <packing>
                    <property name="top_attach">1</property>
                    <property name="bottom_attach">2</property>
                    <property name="x_options">GTK_FILL</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="l_started">
                    <property name="visible">True</property>
                    <property name="selectable">True</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="l_duration">
                    <property name="visible">True</property>
                    <property name="selectable">True</property>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                    <property name="top_attach">1</property>
                    <property name="bottom_attach">2</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="b_reset">
                <property name="label" translatable="yes">Reset</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="image">image2</property>
              </object>
              <packing>
                <property name="position">3</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <object class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <object class="GtkButton" id="button1">
                <property name="label" translatable="yes">gtk-close</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="0">button1</action-widget>
    </action-widgets>
  </object>
  <object class="GtkImage" id="image1">
    <property name="visible">True</property>
    <property name="stock">gtk-edit</property>
  </object>
  <object class="GtkImage" id="image2">
    <property name="visible">True</property>
    <property name="stock">gtk-clear</property>
  </object>
</interface>
"""

def format_bytes(size):
	ret = 0.0
	size = float(size)
	suffix = ""
	if size < 1024:
		ret = size
		suffix = "B"
	elif size > 1024 and size < (1024*1024):
		ret = size / 1024
		suffix = "KB"
	elif size > (1024*1024) and size < (1024*1024*1024):
		ret = size / (1024*1024)
		suffix = "MB"
	else:
		ret = size / (1024*1024*1024)
		suffix="GB"
		
	return (ret, suffix)
	
class main:
	def __init__(self):
		self.editing = False
		
		self.ins_sig = []
		
		self.builder = gtk.Builder()
		self.builder.add_from_string(ui)
		
		self.storage = Gconf()
		self.storage.connect("property-changed", self.on_property_changed)
		
		self.dialog = self.builder.get_object("dialog")
		self.dialog.connect("response", lambda *args: gtk.main_quit())
		
		self.e_ul = self.builder.get_object("e_ul")
		self.e_dl = self.builder.get_object("e_dl")
		self.e_total = self.builder.get_object("e_total")
		
		self.b_reset = self.builder.get_object("b_reset")
		self.b_reset.connect("clicked", self.on_reset)
		
		
		self.l_started = self.builder.get_object("l_started")
		self.l_duration = self.builder.get_object("l_duration")
		
		self.datetime = None
		
		self.update_time()
			
		self.tb_edit = self.builder.get_object("tb_edit")
		self.tb_edit.connect("toggled", self.on_edit_toggled)
		
		self.on_property_changed(None, "download", self.storage.get("download") or 0)
		self.on_property_changed(None, "upload", self.storage.get("upload") or 0)
		
		self.update_total()
		
		self.dialog.show()
		
		
		gtk.main()
		
	def on_reset(self, button):
		d = gtk.MessageDialog(parent=self.dialog, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format="Are you sure you want to reset the counter?")
		res = d.run()
		d.destroy()	
		if res == gtk.RESPONSE_YES:
			self.storage.set("download", 0)
			self.storage.set("upload", 0)	
			self.storage.set("start_time", int(time.time()))
			self.update_time()
				
		
	def on_insert_text(self, editable, new_text, new_text_length, position):
		if not new_text.isdigit():
			editable.stop_emission("insert-text")
		
	def update_time(self):
		time = self.storage.get("start_time")
		if time:
			self.datetime = datetime.datetime.fromtimestamp(time)

			self.l_started.props.label = str(self.datetime)
			
			delta = datetime.datetime.now() - self.datetime
			
			d = gettext.ngettext("day", "days", delta.days)
			h = gettext.ngettext("hour", "hours", delta.seconds / 3600)
			m = gettext.ngettext("minute", "minutes", delta.seconds % 3600 / 60)

			self.l_duration.props.label = "%d %s %d %s and %d %s" % (delta.days, d, delta.seconds / 3600, h, delta.seconds % 3600 / 60, m)
		else:
			self.l_started.props.label = "Unknown"
			self.l_duration.props.label = "Unknown"		
		
	def update_total(self):
		total = (self.storage.get("download") or 0) + (self.storage.get("upload") or 0)
		(num, suffix) = format_bytes(total)
		self.e_total.set_text("%.2f %s" % (num, suffix))
		
	def on_property_changed(self, storage, key, value):
		if not self.editing:
			if key == "download":
				(num, suffix) = format_bytes(value)
				self.e_dl.set_text("%.2f %s" % (num, suffix))
				self.update_total()
				self.update_time()
			
			elif key == "upload":
				(num, suffix) = format_bytes(value)
				self.e_ul.set_text("%.2f %s" % (num, suffix))			
				self.update_total()
			
	def on_edit_toggled(self, button):
		
		if button.props.active:
			self.ins_sig.append(self.e_dl.connect("insert-text", self.on_insert_text))
			self.ins_sig.append(self.e_ul.connect("insert-text", self.on_insert_text))
			
			self.editing = True
			
			self.e_dl.props.editable = True
			self.e_ul.props.editable = True
			
			self.e_dl.set_text(str(self.storage.get("download") or 0))
			self.e_ul.set_text(str(self.storage.get("upload") or 0))
		else:
			dl = int(self.e_dl.props.text)
			ul = int(self.e_ul.props.text)

			(dl_x, dl_y) = format_bytes(dl)
			(ul_x, ul_y) = format_bytes(ul)
			
			self.e_dl.disconnect(self.ins_sig[0])
			self.e_ul.disconnect(self.ins_sig[1])
			self.ins_sig = []
			
			msg = "Are you sure you want to apply the following values:\nDownload: <b>%.2f %s</b>\nUpload: <b>%.2f %s</b>" % (dl_x, dl_y, ul_x, ul_y)
			d = gtk.MessageDialog(parent=self.dialog, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=msg)
			d.props.use_markup = True
			res = d.run()
			d.destroy()
			
			if res == gtk.RESPONSE_YES:
				self.storage.set("download", dl)
				self.storage.set("upload", ul)
				
			#elif res == gtk.RESPONSE_NO:
			#	button.props.active = True
			#	return
			
			self.e_dl.props.editable = False
			self.e_ul.props.editable = False			
			
			self.editing = False
			self.on_property_changed(None, "download", self.storage.get("download") or 0)
			self.on_property_changed(None, "upload", self.storage.get("upload") or 0)	
		
main()
