## -*- coding: utf-8 -*-
#
# «Bare Console» - The serverside configuration/status console for Mythbuntu Bare
#
# Copyright (C) 2011, Thomas Mashos, for Mythbuntu
#
#
# Mythbuntu-bare 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 2 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 application; if not, write to the Free Software Foundation, Inc., 51
# Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
##################################################################################

from MythbuntuControlCentre.plugin import MCCPlugin
import time
from threading import Thread
import configparser
import sys
import subprocess
import gobject
import socket
import os
import hashlib

CONFIGFILE = "/var/lib/mythtv/bare/mythbuntu-bare.conf"

class BareConsolePlugin(MCCPlugin):
    """Server portion of Mythbuntu Backup and Restore utility"""
    #
    #Load GUI & Calculate Changes
    #

    def __init__(self):
        #Initialize parent class
        information = {}
        information["name"] = "Bare Console"
        information["icon"] = "gtk-stop"
        information["ui"] = "tab_bare_console"
        MCCPlugin.__init__(self,information)

    def captureState(self):
        """Determines the state of the items on managed by this plugin
           and stores it into the plugin's own internal structures"""
        self.changes = {}
        self.status_host_buffer = self.status_text_host.get_buffer()
        self.status_lastbackup_buffer = self.status_text_lastbackup.get_buffer()
        self.status_lastseen_buffer = self.status_text_lastseen.get_buffer()
        self.status_status_buffer = self.status_text_status.get_buffer()
        self.config = configparser.ConfigParser()
        if os.path.exists(CONFIGFILE):
          self.config.read(CONFIGFILE)
          try:
            self.changes['serverip'] = self.config.get("General", "serverip")
          except:
            print("Cannot read serverip, setting default")
            self.changes['serverip'] = subprocess.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]
          try:
            self.changes['managed'] = self.config.get("General", "managed")
          except:
            print("Cannot read managed state, setting default")
            self.changes['managed'] = "False"
          try:
            self.changes['revision'] = self.config.get("General", "revision")
          except:
            print("Cannot read revision, setting default")
            self.changes['revision'] = "0"
          try:
            self.changes['BackupLocation'] = self.config.get("Backup", "storagedir")
          except:
            print("Cannot read Backup Location, setting default")
            self.changes['BackupLocation'] = "/var/lib/mythtv/bare"
          try:
            self.changes['backup_db'] = self.config.get("Backup", "db")
          except:
            print("Cannot read db backup setting, setting default")
            self.changes['backup_db'] = "1"
          try:
            self.changes['backup_schedule'] = self.config.get("Backup", "schedule")
            self.changes['backup_schedule_day'] = self.config.get("Backup", "day")
            self.changes['backup_schedule_hour'] = self.config.get("Backup", "hour")
            self.changes['backup_schedule_minute'] = self.config.get("Backup", "minute")
            self.changes['backup_schedule_weekday'] = self.config.get("Backup", "weekday")
          except:
            print("Cannot read schedule, setting default")
            self.changes['backup_schedule'] = "disabled"
            self.changes['backup_schedule_day'] = "*"
            self.changes['backup_schedule_hour'] = "0"
            self.changes['backup_schedule_minute'] = "00"
            self.changes['backup_schedule_weekday'] = "*"
          try:
            self.changes['serverstoragedir'] = self.config.get("General", "serverstoragedir")
          except:
            print("Cannot read server storage directory, setting default")
            self.changes['serverstoragedir'] = "/var/lib/mythtv/bare/"
          try:
            self.changes['serverport'] = self.config.get("General", "serverport")
          except:
            print("Cannot read server port, setting default")
            self.changes['serverport'] = self.PickUnusedPort()
        else:
          print("Error: Config file not found. Setting defaults")
          self.changes['serverip'] = subprocess.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]
          self.changes['managed'] = "False"
          self.changes['revision'] = "0"
          self.changes['BackupLocation'] = "/var/lib/mythtv/bare"
          self.changes['backup_db'] = "1"
          self.changes['backup_schedule'] = "daily"
          self.changes['backup_schedule_day'] = "*"
          self.changes['backup_schedule_hour'] = "0"
          self.changes['backup_schedule_minute'] = "00"
          self.changes['backup_schedule_weekday'] = "*"
          self.changes['serverstoragedir'] = "/var/lib/mythtv/bare/"
          self.changes['serverport'] = self.PickUnusedPort()

    def applyStateToGUI(self):
        """Takes the current state information and sets the GUI
           for this plugin"""
        self.hide_stuff()
        if self.changes['managed'] == "True":
          self.managed_radiobutton.set_active(True)
        else:
          self.unmanaged_radiobutton.set_active(True)
        self.serverip_entry.set_text(self.changes['serverip'])
        self.port_entry.set_text(str(self.changes['serverport']))
        self.backup_location.set_current_folder(self.changes['BackupLocation'])
        self.db_backup_checkbutton.set_active(int(self.changes['backup_db']))
        self.storage_location.set_current_folder(self.changes['serverstoragedir'])
        if self.changes['backup_schedule'] == 'daily':
          self.schedule_daily_button.set_active(True)
        elif self.changes['backup_schedule'] == 'weekly':
          self.schedule_weekly_button.set_active(True)
          wday = int(self.changes['backup_schedule_weekday'])
          self.weekly_combobox.set_active(wday)
        elif self.changes['backup_schedule'] == 'monthly':
          self.schedule_monthly_button.set_active(True)
          md = int(self.changes['backup_schedule_day'])
          mday = md-1
          self.monthly_combobox.set_active(mday)
        elif self.changes['backup_schedule'] == 'disabled':
          self.schedule_disabled_button.set_active(True)
        if not self.changes['backup_schedule'] == "disabled":
          shour = self.changes['backup_schedule_hour']
          self.schedule_hour_combobox.set_active(int(shour))
          smin = int(self.changes['backup_schedule_minute'])/5
          self.schedule_minute_combobox.set_active(int(smin))
        self.schedule_setter()
       
    def schedule_setter(self,widget=None,data=None):
        self.hbox_schedule.hide()
        self.hbox_schedule_weekly.hide()
        self.hbox_schedule_monthly.hide()
        self.monthly_text_label.hide()
        self.monthly_the_label.hide()
        self.schedule_label_sent.hide()
        self.hbox_time.show()
        texthour = self.schedule_hour_combobox.get_active_text()
        textminute = self.schedule_minute_combobox.get_active_text()
        if self.schedule_weekly_button.get_active():
          self.schedule_label_sent.show()
          self.hbox_schedule.show()
          self.hbox_schedule_weekly.show()
          self.schedule_label_sent.set_text("Scheduled backup will be set to run weekly on "+str(self.weekly_combobox.get_active_text())+" at "+texthour+":"+textminute)
        elif self.schedule_monthly_button.get_active():
          self.schedule_label_sent.show()
          self.monthly_text_label.show()
          self.monthly_the_label.show()
          self.hbox_schedule.show()
          self.hbox_schedule_monthly.show()
          self.schedule_label_sent.set_text("Scheduled backup will be set to run monthly on the "+str(self.monthly_combobox.get_active_text())+" day at "+texthour+":"+textminute)
        elif self.schedule_daily_button.get_active():
          self.schedule_label_sent.show()
          self.schedule_label_sent.set_text("Scheduled backup will be set to run daily at "+texthour+":"+textminute)
        if self.schedule_disabled_button.get_active():
          self.hbox_time.hide()

    def compareState(self):
        """Determines what items have been modified on this plugin"""
        MCCPlugin.clearParentState(self)
        changes = False
        print("*********************")
        if not self.changes['serverip'] == self.serverip_entry.get_text():
          changes = True
          print("serverip")
        if not self.changes['serverport'] == self.port_entry.get_text():
          changes = True
          print("serverport")
        if not self.changes['managed'] == str(self.managed_radiobutton.get_active()) and not self.serverip_entry.get_text() == "127.0.0.1":
          changes = True
          print("managed")
        if not self.changes['managed'] == str(self.managed_radiobutton.get_active()) and self.serverip_entry.get_text() == "127.0.0.1":
          self._markReconfigureUser('Error: Manager IP Address cannot be 127.0.0.1 in managed mode', False)
        if not self.changes['BackupLocation'] == self.backup_location.get_current_folder():
          changes = True
          print("location")
        if not self.changes['serverstoragedir'] == self.storage_location.get_current_folder():
          changes = True
          print("serverstoragedir")
        if self.db_backup_checkbutton.get_active() == True:
          self.db_checkbox = "1"
        else:
          self.db_checkbox = "0"
        if not self.changes['backup_db'] == self.db_checkbox:
          changes = True
          print("db")
        if self.schedule_daily_button.get_active():
          self.schedule = "daily"
        elif self.schedule_weekly_button.get_active():
          self.schedule = "weekly"
        elif self.schedule_monthly_button.get_active():
          self.schedule = "monthly"
        elif self.schedule_disabled_button.get_active():
          self.schedule = "disabled"
        if not self.changes['backup_schedule'] == self.schedule:
          changes = True
          print("schedule")
        if self.schedule == "weekly":
          if not self.changes['backup_schedule_weekday'] == self.weekly_combobox.get_active():
            changes = True
            print("weekday")
        elif self.schedule == "monthly":
          if not self.changes['backup_schedule_day'] == self.monthly_combobox.get_active_text():
            changes = True
            print("day")
        if not self.schedule == "disabled":        
          if not self.changes['backup_schedule_hour'] == self.schedule_hour_combobox.get_active_text():
            print("hour")
            changes = True
          if not self.changes['backup_schedule_minute'] == self.schedule_minute_combobox.get_active_text():
            print("minute")
            changes = True
        if changes == True:
          self._markReconfigureUser('Update Configuration', True)

    def hide_stuff(self):
        self.backup_u1_button.hide()
        self.backup_dropbox_button.hide()
        self.hbox_backup_to.hide()
        self.alignment_preconfigured_label.hide()

    def on_managed_toggled(self,widget=None,data=None):
        if self.managed_radiobutton.get_active():
          self.vbox_ip.show()
          self.vbox_backup_location.show()
          self.vbox_set_schedule.show()
        else:
          self.vbox_ip.hide()
          self.vbox_backup_location.hide()
          self.vbox_set_schedule.hide()

    def PickUnusedPort(self):
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s.bind(('localhost', 0))
      addr, port = s.getsockname()
      s.close()
      return port

    #
    # Callbacks
    #
    def on_refresh_button_clicked(self,widget=None,data=None):
        """Shows an example of how a callback can do stuff"""
        self.update_status_window()

    def on_clear_button_clicked(self,widget,data=None):
        """Shows an example of how a callback can do stuff"""
        f = open("/var/lib/mythtv/bare/client.db", 'w')
        f.write("HOST\tLASTBACKUP\tLASTSEEN\tSTATUS")
        f.close()
        self.update_status_window()

    def update_status_thread(self):
#        while True:
        self.update_status_window()
        print("update")
        time.sleep(1)
        return True

    def update_status_window(self):
        f = open("/var/lib/mythtv/bare/client.db")
        host_lines = ""
        lastbackup_lines = ""
        lastseen_lines = ""
        status_lines = ""
        for l in f:
          try:
            line = l.strip('\n')
            host, lastbackup, lastseen, status = line.split('\t')
            if not host == 'HOST':
              host_lines += host+'\n'
              lastbackup_lines += lastbackup+'\n'
              lastseen_lines += lastseen+'\n'
              status_lines += status+'\n'
          except:
            print("Invalid line in client.db")
        f.close
        self.status_host_buffer.set_text(host_lines)
        self.status_lastbackup_buffer.set_text(lastbackup_lines)
        self.status_lastseen_buffer.set_text(lastseen_lines)
        self.status_status_buffer.set_text(status_lines)

    #
    # Process selected activities
    #

    def user_scripted_changes(self,reconfigure):
        """Local changes that can be performed by the user account.
           This function will be ran by the frontend"""
        self.emit_progress("Starting up", 20)
        time.sleep(2)
        for item in reconfigure:
            if item == "Update Configuration":
              newconfig = configparser.ConfigParser()
              self.emit_progress("Reading configuration file", 30)
              try:
                newconfig.read(CONFIGFILE)
                revision=int(newconfig.get("General", "revision"))
                revision += 1
              except:
                revision = 0
                newconfig.add_section("General")
                newconfig.add_section("Backup")
              self.emit_progress("Setting general settings", 40)
              newconfig.set("General", "serverip", self.serverip_entry.get_text())
              newconfig.set("General", "serverport", self.port_entry.get_text())
              newconfig.set("General", "managed", self.managed_radiobutton.get_active())
              newconfig.set("General", "revision", revision)
              newconfig.set("General", "serverstoragedir", self.storage_location.get_current_folder())
              self.emit_progress("Setting backup settings", 50)
              newconfig.set("Backup", "storagedir", self.backup_location.get_current_folder())
              newconfig.set("Backup", "db", self.db_checkbox)
              newconfig.set("Backup", "schedule", self.schedule)
              if self.schedule == "weekly":
                newconfig.set("Backup", "weekday", self.weekly_combobox.get_active())
                newconfig.set("Backup", "day", "*")
              elif self.schedule == "monthly":
                newconfig.set("Backup", "weekday", "*")
                newconfig.set("Backup", "day", self.monthly_combobox.get_active_text())
              elif self.schedule == "monthly":
                newconfig.set("Backup", "weekday", "*")
                newconfig.set("Backup", "day", "*")
              else:
                newconfig.set("Backup", "weekday", "*")
                newconfig.set("Backup", "day", "*")
              self.emit_progress("Setting schedule", 60)
              if not self.schedule == "disabled":        
                newconfig.set("Backup", "hour", self.schedule_hour_combobox.get_active_text())
                newconfig.set("Backup", "minute", self.schedule_minute_combobox.get_active_text())
              newconfig.set("General", "checksum", "XXXXXXXXXX")
              with open(CONFIGFILE, 'w') as conffile:
                newconfig.write(conffile)
              self.emit_progress("Generating hash", 70)
              h = hashlib.sha1()
              f = open(CONFIGFILE, "rb")
              h.update(f.read())
              hsh = h.hexdigest()
              f.close()
              hashconfig = configparser.ConfigParser()
              hashconfig.read(CONFIGFILE)
              hashconfig.set("General", "checksum", hsh)
              self.emit_progress("Saving configuration file", 80)
              with open(CONFIGFILE, 'w') as conffile:
                hashconfig.write(conffile)
        self.emit_progress("Finished setting configuration", 90)
        time.sleep(2)
