#!/usr/bin/python

# Adapted from flexgridsizer example at http://zetcode.com/wxpython/layout/

import wx
import os
import sys
import urllib2
import datetime

warning_message = """
This is free software provided under the GNU GPL license.
Nightime usage is calculated as usage in sessions that start after 10 pm and before 6 am.
Don't blame me if this changes or if the usage data is not correct for any other reason.
THIS PROGRAM COMES WITH NO WARRANTY

Author: Raja S <rajajs@gmail.com>
"""

class Reliance_Usage():
    def __init__(self, frame, phone_number, bill_date):
        """phone number is a string, billdate is an int 1-28"""
        self.phone_number = phone_number
        self.bill_date = bill_date
        self.frame = frame
        self.get_usage()
        
    def get_usage(self):
        self.frame.display_message('constructing url ...')
        end_date, start_date = self.get_dates()
        url = ''.join(['http://myservices.relianceada.com/datausage/',
                       'jsp/ProcessCDRRequest?Mdn=',
                       self.phone_number,
                       '&StartDate=%s&EndDate=%s' %(start_date, end_date),
                       '&ProductType=1&RequestType=Download'])

        self.frame.display_message('connecting ...')
        csv = urllib2.urlopen(url).read()
        self.frame.display_message('calculating ...')
        csvlines = csv.split('\n')[1:-1]

        try:
            dayupload = [line.split(',')[3] for line in csvlines
                         if 6<self.hour(line.split(':')[1])<22]
            daydownload = [line.split(',')[4] for line in csvlines
                           if 6<self.hour(line.split(':')[1])<22]
            nightupload = [line.split(',')[3] for line in csvlines
                           if self.hour(line.split(':')[1])>22 or
                           self.hour(line.split(':')[1])<6]
            nightdownload = [line.split(',')[4] for line in csvlines
                             if self.hour(line.split(':')[1])>22 or
                             self.hour(line.split(':')[1])<6]
        except IndexError:
            self.frame.display_message('Failed')
            self.usage = 'Failed to retrieve records'
            return
            
        # all values are in kb
        self.total_dayupload = sum(map(float, dayupload))
        self.total_daydownload = sum(map(float, daydownload))
        self.total_nightupload = sum(map(float, nightupload))
        self.total_nightdownload = sum(map(float, nightdownload))

        self.usage = '\n\n'.join(['',
                 'Daytime download   - %s' % (self.format_usage(self.total_daydownload)),
                 'Daytime upload     - %s' % (self.format_usage(self.total_dayupload)),
                 'Nighttime download - %s' % (self.format_usage(self.total_nightdownload)),
                 'Nighttime upload   - %s' % (self.format_usage(self.total_nightupload))])

    def format_usage(self, usage):
        """format usage that is available as kb into
        more readable format"""
        gb, rem = divmod(usage, 1024 * 1024)
        mb, kb = divmod(rem, 1024)
        return '%d GB, %d MB, %d KB' % (gb, mb, kb)

    def get_dates(self):
        """Return todays date and the first day of the
        current billing cycle. Bill date is day of month
        when billing cycle starts"""
        today = datetime.datetime.today()

        if self.bill_date < today.day:
            # billing cycle starts this month
            start_date = datetime.datetime(today.year,
                                           today.month, self.bill_date)
        else:
            # billing cycle extends from last month
            if today.month > 1:
                start_date = datetime.datetime(today.year,
                                               today.month-1, self.bill_date)
            else:
                # handle when billing cycle starts in prev year
                start_date = datetime.datetime(today.year-1,
                                               12, self.bill_date)

        return (today.strftime('%Y-%m-%d'), start_date.strftime('%Y-%m-%d'))

    def hour(self, timestring):
        """Get the value for hour from a string representing time
        example: 16:10:23 will give 16"""
        return int(timestring.split(':')[0])


class MainFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(450, 300))

        panel = wx.Panel(self, -1)
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        fgs = wx.FlexGridSizer(4, 2, 9, 25)
        label1 = wx.StaticText(panel, -1, 'Phone number',
                               style=wx.ALIGN_CENTER_VERTICAL)
        label2 = wx.StaticText(panel, -1, 'Billing starts on',
                               style=wx.ALIGN_CENTER_VERTICAL)
        label3 = wx.StaticText(panel, -1, 'Usage',
                               style=wx.ALIGN_CENTER_VERTICAL)
        
        self.phone_entry = wx.TextCtrl(panel, -1)
        self.date_entry = wx.SpinCtrl(panel, -1)
        self.date_entry.SetRange(1,28)
        self.results = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY)
        ct4 = wx.Button(panel, -1, "Check now")
        ct5 = wx.Button(panel, wx.ID_EXIT, "Quit")

        ct4.Bind(wx.EVT_BUTTON, self.OnCheck)
        ct5.Bind(wx.EVT_BUTTON, self.OnQuit)
        self.Bind(wx.EVT_CLOSE, self.OnQuit)
        
        fgs.AddMany([(label1), (self.phone_entry, 1, wx.EXPAND),
                     (label2), (self.date_entry, 1, wx.EXPAND),
                     (label3, 1, wx.EXPAND), (self.results, 1, wx.EXPAND),
                     (ct4), (ct5)])
        fgs.AddGrowableRow(2, 1)
        fgs.AddGrowableCol(1, 1)
        hbox.Add(fgs, 1, wx.ALL | wx.EXPAND, 15)
        panel.SetSizer(hbox)

        self.CreateStatusBar()
        self.Centre()
        self.Show(True)

        self.input_file = os.path.join(os.path.expanduser('~'),
                                       'reliance_check.txt')
        self.phone_number, self.bill_date = self.load_input()
        self.phone_entry.write(self.phone_number)
        self.date_entry.SetValue(self.bill_date)
        self.results.write(warning_message)
        
    def OnCheck(self, event):
        """Check usage"""
        self.display_message('checking usage')
        self.phone_number = self.phone_entry.GetValue()
        self.bill_date = self.date_entry.GetValue()

        try:
            dummy = int(self.phone_number)
        except ValueError:
            self.display_message('Not a valid phone number')
            return

        usage = Reliance_Usage(self, self.phone_number, self.bill_date)
        self.results.Clear()
        self.results.write(usage.usage)
        self.display_message('Done')
        
    def OnQuit(self, event):
        self.save_input()
        sys.exit(0)

    def display_message(self, msg):
        #print msg
        self.SetStatusText(msg)

    def load_input(self):
        """load stored values"""

        try:
            fi = open(self.input_file, 'r')
            phone_number = fi.readline().rstrip('\n')
            bill_date = int(fi.readline().rstrip('\n'))
            fi.close
        except:
            # defaults 
            phone_number, bill_date = '0', 1
        return phone_number, bill_date
        
    def save_input(self):
        """save input phone_number and date"""
        fi = open(self.input_file, 'w')
        fi.write(self.phone_number + '\n')
        fi.write(str(self.bill_date))
        fi.close()
        
app = wx.App()
MainFrame(None, -1, 'Reliance Usage Check')
app.MainLoop()

