#!/usr/bin/python
#
# Copyright (c) 2013 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#           http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import os
import threading

from gi.repository import Gtk, GObject, Gdk, WebKit, Gio
from redhat_support_lib import api
from urlparse import urlparse

GObject.threads_init()
Gdk.threads_init()

#Switch to site-package dir
os.chdir("/usr/lib/python2.7/site-packages/redhat_access_gui/")


#Tie the GtkBuilder assets to methods
class Handlers:

    #Handle the exit
    def onDeleteWindow(self, *args):
        rha.quit()

    #Hide the about window
    def hideAbout(self, *args):
        rha.windowabout.hide()

    #Hide the failure dialog
    def hideFailure(self, *args):
        rha.dialogFailure.hide()

    #When the icons are pressed do something
    def searchBox_icon_press_cb(self, entry, icon_pos, event):
        if icon_pos == Gtk.EntryIconPosition.PRIMARY:
            if entry.get_text() != "":
                self.searchDone(entry)
        elif icon_pos == Gtk.EntryIconPosition.SECONDARY:
            entry.set_text("")

    #Gets called each time the box is changed
    def searchBox_changed_cb(self, entry):
        if entry.get_text() != "":
            entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "edit-clear-symbolic")
        else:
            entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "")


    #User has hit enter in the search box
    def searchDone(self, searchEntry):
        rha.spinnerSearch.set_visible(True)
        t = threading.Thread(
            target=self.doSearch,
            args=(
                rha.usernameEntry.get_text(),
                rha.passwordEntry.get_text(),
                searchEntry.get_text()
            )
        )
        t.start()

    def doSearch(self, username, password, searchStr):
        try:
            solutions = rha.strata.problems.diagnoseStr(searchStr)
        except:
            Gdk.threads_enter()
            rha.spinnerSearch.set_visible(False)
            rha.dialogFailure.show_all()
            Gdk.threads_leave()
            return

        Gdk.threads_enter()
        rha.spinnerSearch.set_visible(False)
        rha.solList.clear()
        rha.solListView.set_sensitive(True)
        for sol in solutions:
            for link in sol.get_link():
                parsed = urlparse(link.get_uri())
                sol_id = os.path.basename(parsed[2])
                rha.solList.append([sol_id, link.get_value()])
        Gdk.threads_leave()

    #User has clicked a row to view a solution
    def titleClicked(self, treeview, path, view_column):
        solIter = rha.solList.get_iter(path)
        value = rha.solList.get_value(solIter, 0)
        rha.spinnerSearch.set_visible(True)
        try:
            solution = rha.strata.solutions.get(str(value))
        except:
            import traceback
            traceback.print_exc(file=sys.stdout)
            rha.spinnerSearch.set_visible(False)
            rha.dialogFailure.show_all()
            return

        html = "<html><head>"
        html = html + "<style>" + rha.bootstrapcss + "</style>"
        html = html + "</head><body style='margin: 20px'>\n"
        try:
            soln = solution.environment.get_html()
            html = html + "<h3>Environment</h3>"
            html = html + soln
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            pass

        html = html + "<h3>Issue</h3>"
        html = html + solution.issue.get_html()
        try:
            res = solution.resolution.get_html()
            html = html + "<h3>Resolution</h3>"
            html = html + res
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            pass

        html = html + "</body></html>"
        rha.spinnerSearch.set_visible(False)
        rha.solWebView.load_string(html, "text/html", "UTF-8", "/")
        rha.windowSolution.set_title(solution.title)
        rha.windowSolution.connect("destroy", self.showSearch)
        rha.backbutton.connect("clicked", self.showSearch)
        rha.winMainX, rha.winMainY = rha.windowSearch.get_position()
        rha.windowSolution.show_all()
        rha.windowSearch.hide()

    #User has clicked a row to view a solution
    def titleClicked2(self, treeview, path, view_column):
        solIter = rha.solListDiag.get_iter(path)
        value = rha.solListDiag.get_value(solIter, 0)
        try:
            solution = rha.strata.solutions.get(str(value))
        except:
            rha.dialogFailure.show_all()
        html = "<html><head>"
        html = html + "<style>" + rha.bootstrapcss + "</style>"
        html = html + "</head><body>\n"
        html = html + "<h3>Environment</h3>"
        html = html + solution.environment.get_html()
        html = html + "<h3>Issue</h3>"
        html = html + solution.issue.get_html()
        html = html + "<h3>Resolution</h3>"
        html = html + solution.resolution.get_html()
        html = html + "</body></html>"
        rha.solWebView.load_string(html, "text/html", "UTF-8", "/")
        rha.windowSolution.set_title(solution.title)
        rha.windowSolution.connect("destroy", self.showDiagnose)
        rha.backbutton.connect("clicked", self.showDiagnose)
        rha.windowSolution.show_all()
        #rha.windowdiagnose.hide()

    def showMain(self, userdata):
        rha.windowSearch.show_all()
        rha.windowSearch.move(rha.winMainX, rha.winMainY)
        rha.windowSolution.hide()

    def showSearch(self, userdata):
        #rha.windowdiagnose.hide()
        rha.windowSolution.hide()
        rha.windowSearch.show_all()
        #rha.tabsearch.set_active(True)
        #rha.tabdiagnose.set_active(False)

    def showDiagnose(self, userdata):
        rha.windowSearch.hide()
        rha.windowSolution.hide()
        #rha.windowdiagnose.show_all()
        rha.tabsearch1.set_active(False)
        rha.tabdiagnose1.set_active(True)

    def doDiagnose(self, fileChooser):
        if fileChooser.get_filename() is not None:
            t = threading.Thread(
                target=self.doStrataDiag,
                args=(
                    rha.usernameEntry.get_text(),
                    rha.passwordEntry.get_text(),
                    fileChooser.get_filename()
                )
            )
            t.start()

    def doStrataDiag(self, username, password, filename):
        try:
            solutions = rha.strata.problems.diagnoseFile(filename)
        except:
            Gdk.threads_enter()
            rha.dialogFailure.show_all()
            Gdk.threads_leave()

        Gdk.threads_enter()
        rha.solListDiag.clear()
        for sol in solutions:
            for link in sol.get_link():
                parsed = urlparse(link.get_uri())
                sol_id = os.path.basename(parsed[2])
                rha.solListDiag.append([sol_id, link.get_value()])
        Gdk.threads_leave()

    #Handle the initial login
    def handleLogin(self, something):
        rha.spinnerLogin.set_visible(True)
        rha.buttonLogin.set_sensitive(False)
        rha.passwordEntry.set_sensitive(False)
        rha.usernameEntry.set_sensitive(False)
        t = threading.Thread(
            target=self.doLogin,
            args=(
                rha.usernameEntry.get_text(),
                rha.passwordEntry.get_text()
            )
        )
        t.start()

    def doLogin(self, username, password):
        try:
            #TODO: Make a method that does a GET on /rs/
            rha.strata = api.API(
                username,
                password,
            userAgent="Red Hat Access GUI 1.0.0-6")
            rha.strata.solutions.get("439593")
            #Need to clean strata up
            Gdk.threads_enter()
            rha.usernameEntry.set_sensitive(True)
            rha.buttonLogin.set_sensitive(True)
            rha.passwordEntry.set_sensitive(True)
            rha.spinnerLogin.set_visible(False)
            rha.windowSearch.show_all()
            rha.windowLogin.hide()
            Gdk.threads_leave()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            import traceback
            traceback.print_exc(file=sys.stdout)
            rha.strata.disconnect()
            rha.strata = None
            Gdk.threads_enter()
            rha.buttonLogin.set_sensitive(True)
            rha.usernameEntry.set_sensitive(True)
            rha.passwordEntry.set_sensitive(True)
            rha.spinnerLogin.set_visible(False)
            loginfailed = rha.builder.get_object("labelloginfailed")
            loginfailed.set_visible(True)
            Gdk.threads_leave()

    def showPasswordToggle(self, button):
        if button.get_active():
            rha.passwordEntry.set_visibility(True)
        else:
            rha.passwordEntry.set_visibility(False)


class RedHatAccess(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self, application_id="RedHat.Access")

    def do_activate(self):
        self.windowLogin.show_all()

    def do_startup(self):
        Gtk.Application.do_startup(self)
        strata = None
        self.builder = Gtk.Builder()
        self.builder.add_from_file("redhat_access.ui")
        self.builder.connect_signals(Handlers())

        # create a menu
        menu = Gio.Menu()
        # append to the menu three options
        menu.append("Logout", "app.logout")
        menu.append("About", "app.about")
        menu.append("Quit", "app.quit")
        # set the menu as menu of the application
        self.set_app_menu(menu)

        # option "about"
        about_action = Gio.SimpleAction.new("about", None)
        about_action.connect("activate", self.about_cb)
        self.add_action(about_action)

        # option "quit"
        quit_action = Gio.SimpleAction.new("quit", None)
        quit_action.connect("activate", self.quit_cb)
        #self.add_accelerator("<Primary>q", "app.quit", None)
        self.add_action(quit_action)

        #Grab the objects from Glade
        #Login window objects
        self.windowLogin = self.builder.get_object("windowlogin")
        self.windowLogin.connect("key-press-event", self.keypress)
        self.windowLogin.set_property("application", self)
        self.windowLogin.set_wmclass("Red Hat Access", "Red Hat Access")
        self.windowLogin.set_default_icon_from_file("redhat-logo.png")
        self.usernameEntry = self.builder.get_object("entryusername")
        self.passwordEntry = self.builder.get_object("entrypassword")
        self.buttonLogin = self.builder.get_object("buttonlogin")
        self.spinnerLogin = self.builder.get_object("spinner1")

        #Search window objects
        self.windowSearch = self.builder.get_object("windowmain")
        self.windowSearch.connect("key-press-event", self.keypress)
        self.windowSearch.set_property("application", self)
        self.windowSearch.set_wmclass("Red Hat Access", "Red Hat Access")
        self.windowSearch.set_default_icon_from_file("redhat-logo.png")
        self.solList = self.builder.get_object("liststore1")
        self.solList.append(["", "Please use the search bar above to search the Red Hat Knowledgebase for Articles and Solutions"])
        self.solListView = self.builder.get_object("treeview1")
        self.solListView.set_sensitive(False)
        self.spinnerSearch = self.builder.get_object("spinner2")
        #Save search window position
        self.winMainX = 0
        self.winMainY = 0
        #Search window tabs, currently disabled
        #self.tabsearch = self.builder.get_object("tabSearch")
        #self.tabdiagnose = self.builder.get_object("tabDiagnose")

        #Diagnose window objects
        #self.windowdiagnose = self.builder.get_object("windowdiagnose")
        #self.windowdiagnose.set_property("application", self)
        #self.windowdiagnose.set_wmclass("Red Hat Access", "Red Hat Access")
        #self.windowdiagnose.set_default_icon_from_file("redhat-logo.png")
        #self.solListDiag = self.builder.get_object("liststore2")
        #Diagnose window tabs, currently disabled
        #self.tabsearch1 = self.builder.get_object("tabSearch1")
        #self.tabdiagnose1 = self.builder.get_object("tabDiagnose1")

        #Solution window objects
        self.windowSolution = self.builder.get_object("windowsolution")
        self.windowSolution.connect("key-press-event", self.keypress)
        self.windowSolution.set_property("application", self)
        self.windowSolution.set_wmclass("Red Hat Access", "Red Hat Access")
        self.windowSolution.set_default_icon_from_file("redhat-logo.png")
        self.scrollwinsolution = \
            self.builder.get_object("scrolledwindowsolution")
        self.solWebView = WebKit.WebView()
        self.scrollwinsolution.add(self.solWebView)
        self.backbutton = self.builder.get_object("backButton")

        #About window
        self.windowabout = self.builder.get_object("aboutrhaccess")

        self.dialogFailure = self.builder.get_object("dialog_failure")

        #Load CSS
        cssfile = open("bootstrap.css", "r")
        self.bootstrapcss = cssfile.read()
        cssfile.close()

    def keypress(self, widget, event):
        keyname = Gdk.keyval_name(event.keyval)
        ctrl = event.state & \
                Gdk.ModifierType.CONTROL_MASK
        if ctrl:
            if keyname == 'q':
                self.quit()

    # callback function for "about"
    def about_cb(self, action, parameter):
        self.windowabout.show_all()

    # callback function for "quit"
    def quit_cb(self, action, parameter):
        self.quit()


#Gdk.threads_enter()
#This is so the ctrl+c signal handler will actually work
if __name__ == '__main__':
    import signal
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    rha = RedHatAccess()
    exit_status = rha.run(sys.argv)
#Gdk.threads_leave()
