#!/usr/bin/env python3
#
# Copyright © 2016 Johnathan "Shaggytwodope" Jenkins <twodopeshaggy@gmail.com>
# Updated by Ralphy <postmaster@unlockforus.com>
# Forked by Paul Sherman <psherman2001@gmail.com>
# Distributed under terms of the GPL2 license.

import os
import sys
import webbrowser
import subprocess
import fcntl
import tkinter
from configparser import ConfigParser
import gi
gi.require_version('WebKit2', '4.0')
from gi.repository import WebKit2 as webkit
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf
from os import stat as os_stat
import datetime
import http.client as httplib


cpl_xpm = [
"16 16 93 2",
"  	c None",
". 	c #001A21",
"+ 	c #004658",
"@ 	c #001519",
"# 	c #004A5D",
"$ 	c #00CAFF",
"% 	c #003E4F",
"& 	c #121F22",
"* 	c #3A5D66",
"= 	c #0E191D",
"- 	c #5D5D5D",
"; 	c #FFFFFF",
"> 	c #E9E7E7",
", 	c #AF9F9E",
"' 	c #CDC5C4",
") 	c #4E4E4E",
"! 	c #D1C8C7",
"~ 	c #EDECEC",
"{ 	c #A18988",
"] 	c #ED3E36",
"^ 	c #9A5855",
"/ 	c #BFB6B6",
"( 	c #4C4C4C",
"_ 	c #CDC0BF",
": 	c #B1453F",
"< 	c #974B47",
"[ 	c #934C49",
"} 	c #FF433A",
"| 	c #BB453F",
"1 	c #8C5855",
"2 	c #C33A33",
"3 	c #9E7977",
"4 	c #D1C9C9",
"5 	c #B24540",
"6 	c #E93E37",
"7 	c #9A7876",
"8 	c #4B4B4B",
"9 	c #B3A5A4",
"0 	c #934946",
"a 	c #DE4039",
"b 	c #9F5754",
"c 	c #B24742",
"d 	c #D03C35",
"e 	c #907D7C",
"f 	c #D0CAC9",
"g 	c #A08382",
"h 	c #EA3D35",
"i 	c #9B5E5C",
"j 	c #B0A09F",
"k 	c #F54038",
"l 	c #95514D",
"m 	c #B29E9E",
"n 	c #9E4D48",
"o 	c #D2423A",
"p 	c #9D4F4B",
"q 	c #D4D2D2",
"r 	c #917574",
"s 	c #F44037",
"t 	c #F84138",
"u 	c #9E4642",
"v 	c #8C6260",
"w 	c #494949",
"x 	c #FEFEFE",
"y 	c #8D4E4B",
"z 	c #FD423A",
"A 	c #C63933",
"B 	c #C13A33",
"C 	c #CBC6C6",
"D 	c #484848",
"E 	c #A79594",
"F 	c #DC3D35",
"G 	c #EB3F37",
"H 	c #EC3E36",
"I 	c #FC4239",
"J 	c #DA3A33",
"K 	c #845351",
"L 	c #F8F8F8",
"M 	c #8C5B58",
"N 	c #9A7978",
"O 	c #7F605E",
"P 	c #974945",
"Q 	c #B1A4A3",
"R 	c #844946",
"S 	c #D1C6C5",
"T 	c #B2A2A1",
"U 	c #9F4B47",
"V 	c #906765",
"W 	c #474747",
"X 	c #1B1B1B",
"Y 	c #4D4D4D",
"Z 	c #525252",
"` 	c #585858",
" .	c #131313",
". + + + + + + + + + + + + + + @ ",
"# $ $ $ $ $ $ $ $ $ $ $ $ $ $ % ",
"& * * * * * * * * * * * * * * = ",
"- ; ; ; ; ; ; ; > , ' ; ; ; ; ) ",
"- ; ; ; ; ; ! ~ { ] ^ ; / ; ; ( ",
"- ; ; ; ; _ : < [ } | 1 2 3 ; ( ",
"- ; ; ; ; 4 5 } } } } } 6 7 ; 8 ",
"- ; ; ; > 9 0 } a b c } d e f 8 ",
"- ; ; ; g h } } i ; j h } k l 8 ",
"- ; ; ; m n o } p q r s t u v w ",
"- ; ; ; ; x y } z A h } B C ; D ",
"- ; ; ; ; E F G H } I J } K ; D ",
"- ; ; ; ; L M N O } P Q R S ; D ",
"- ; ; ; ; ; x ; T U V ; x ; ; W ",
"X Y Y Y Y Y Y Y Y Y Y Y Z ` )  .",
"                                "]

cpl_icon = GdkPixbuf.Pixbuf.new_from_xpm_data(cpl_xpm)

def run_once():
    global fh
    fh = open(os.path.realpath(__file__), 'r')
    try:
        fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except:
        run_once_dialog()


def run_once_dialog():
    window = Gtk.Window()
    dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.OTHER,
                                                          Gtk.ButtonsType.OK)
    dialog.set_default_size(200, 140)
    dialog.set_title("Absolute Control Panel")
    dialog.set_transient_for(window)
    dialog.format_secondary_text("There is another instance already running.")
    response = dialog.run()

    if response == Gtk.ResponseType.OK:
        dialog.destroy()
        sys.exit()

    dialog.destroy()


def execute(command, ret=True):
	if ret is True:
		p = os.popen(command)
		return p.readline()
	else:
		p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
		return p.stdout


def on_decide_policy(webview, decision, decision_type):

	def deny():
		decision.ignore()
		return True

	if decision_type == webkit.PolicyDecisionType.NAVIGATION_ACTION:

		navigation_action = decision.get_navigation_action()
		navigation_request = navigation_action.get_request()
		navigation_type = navigation_action.get_navigation_type()
		url = navigation_request.get_uri()

		if url.startswith("file://"):
			pass
		else:
			command = url[8:]
			if command is not None:
				subprocess.Popen(command, shell=True)
				deny()
			else:
				deny()
	return False



def connected(host='https://google.com'):
    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False


def mem_info():
    f = open('/proc/meminfo')
    for line in f:
        if line.startswith('MemTotal:'):
            mem_total = (int(line.split()[1]) * 1024.0)
        elif line.startswith('Active:'):
            mem_active = (int(line.split()[1]) * 1024.0)
        elif line.startswith('Inactive:'):
            mem_inactive = (int(line.split()[1]) * 1024.0)
        elif line.startswith('MemFree:'):
            mem_free = (int(line.split()[1]) * 1024.0)
        elif line.startswith('Cached:'):
            mem_cached = (int(line.split()[1]) * 1024.0)
        elif line.startswith('Buffers:'):
            mem_buffers = (int(line.split()[1]) * 1024.0)
    f.close()

    return (mem_total, mem_active, mem_inactive, mem_free, mem_cached,
                    mem_buffers)


def apt_info():
    pass


def get_info(info):
	try:
		if info == "os":
			try:
				for line in open('/etc/os-release'):
					rec = line.strip()
					if rec.startswith('PRETTY_NAME'):
					   oslist = line.split('"')[1::2]
					   osin = ' '.join([str(elem) for elem in oslist])
			except:
				osin = "Absolute Linux"
			return osin
		if info == "desk":
			desk_ses = "Spacefm File Manager, with Icewm Window Manager and arox (Rox-Filer Fork)"
			return desk_ses

		if info == "arc":
			return os.uname()[4]
		if info == "host":
			return os.uname()[1]
		if info == "kernel":
			return "{0} {1}".format(os.uname()[0], os.uname()[2])

		if info == "processor":
			proc = execute("grep 'model name' /proc/cpuinfo").split(':')[1]
			return proc
		if info == "mem":
			total, active, inactive, free, cached, buffers, = mem_info()
			pie = ((int(total) - int(free)) - (int(buffers) + int(cached)))
			mem_usage = float(pie) * 100 / float(total)
			ramdis = "%14dMB (Used: %8dMB %7.2f%%)" % (
				int(total) / 1048576, pie / 1024 / 1024, mem_usage)

			return ramdis
		if info == "gfx":
			return execute("lspci | grep VGA").split('controller:')[1].split(
					'(rev')[0].split(',')[0]
		if info == "audio":
			audio = execute("lspci | grep 'Audio device:'")
			if len(audio) == 0:
				return execute("lspci | grep audio").split('controller:')[
					1].split('(rev')[0].split(',')[0]
			else:
				return execute("lspci | grep Audio").split('device:')[1].split(
					'(rev')[0].split(',')[0]
		if info == "disk":
			p1 = subprocess.Popen(
					['df', '-Tlh', '--total', '-t', 'ext4', '-t', 'ext3', '-t',
						'ext2', '-t', 'reiserfs', '-t'
						'jfs', '-t', 'ntfs', '-t', 'fat32', '-t', 'btrfs', '-t',
						'fuseblk', '-t', 'xfs'],
					stdout=subprocess.PIPE).communicate()[0].decode("Utf-8")
			total = p1.splitlines()[-1]
			used = total.split()[3].replace(total.split()[3][-1:],
				" " + total.split()[3][-1:] + "B")
			size = total.split()[2].replace(total.split()[2][-1:],
				" " + total.split()[2][-1:] + "B")
			disk = "{0} (Used: {1})".format(size, used)
			return disk
		if info == "netstatus":
			if connected():
				status = '<font color=green>Active</font>'
			else:
				status = '<font color=red>Not connected</font>'
			return status
		if info == "netip":
			ip = execute("hostname -I").split(' ')
			if len(ip) > 1:
				ip = ip[0]
			elif ip == "":
				ip = 'None'
			else:
				ip = 'None'
			return ip
		if info == "gateway":
			gateway = execute("route -n | grep 'UG[ \t]' | awk '{print $2}'")
			if len(gateway) == 0:
				gateway = 'None'
			return gateway
		if info == "pubip":
			pip = execute("dig +short myip.opendns.com @resolver1.opendns.com")
			if len(pip) == 0:
				pip = 'None'
			return pip
	except (OSError, TypeError, Exception) as e:
		print(e)
		return " "


def which(program):
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file
    return None


def get_modules(section):
    window = Gtk.Window()
    try:
        mod_dir = os.listdir("{0}/modules/{1}/".format(app_dir, section))
        mod_dir.sort()
    except Exception:
        dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, 'Error Importing Module Data')
        dialog.set_default_size(400, 250)
        dialog.format_secondary_text("No modules could be found." + " Please reinstall " + appname)
        dialog.set_transient_for(window)
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            dialog.destroy()
            sys.exit()
        dialog.destroy()

    if isinstance(mod_dir, list) and len(mod_dir) < 1:
        return "<p>\"no modules found!\"</p>"
    else:
        parser = ConfigParser()
        admin = ""
        mod_dir.sort()
        for i in mod_dir:
            parser.read("{0}/modules/{1}/{2}".format(app_dir, section, i))
            command = parser.get('module', 'command')

            chk = command.split(' ')[0]
            if chk == "gksudo":
                chk = command.split(' ')[1]
            elif chk == "gksu":
                chk = command.split(' ')[1]
            checking = which(chk)
            if checking is not None:
                ico = parser.get('module', 'ico')
                ico = "{0}/frontend/icons/modules/{1}".format(app_dir, ico)
                name = parser.get('module', 'name')
                desc = parser.get('module', 'desc')
                command = command.replace("'", ''' \\' ''')

                admin += '''<div class="launcher" onclick="location.href='admin://{0}'" >
                <img src="{1}" onerror='this.src = "/usr/share/controlpanel/frontend/icons/modules/notfound.png"'/>
                <h3>{2}</h3>
                <span>{3}</span>
                </div>'''.format(command, ico, name, desc)
        return admin


def frontend_fill():
    filee = open("{0}/frontend/default.html".format(app_dir), "r")
    page = filee.read()
    for i in ['os', 'desk', 'arc', 'processor', 'mem', 'gfx', 'audio', 'disk',
                        'kernel', 'updates', 'host', 'netstatus', 'netip', 'gateway', 'pubip']:
        page = page.replace("{%s}" % i, str(get_info(i)))
    sections = ['software', 'system', 'desktop', 'hardware', 'networking']
    sections.sort()
    for i in sections:
        page = page.replace("{%s_list}" % i, get_modules(i))
    filee.close()
    return page


def main():
	global browser
	global window
	frontend = frontend_fill()
	window = Gtk.Window()
	window.connect('destroy', Gtk.main_quit)
	window.set_title(appname)
	window.set_icon(cpl_icon)
	rootsize = tkinter.Tk()
	if rootsize.winfo_screenheight() > 700:
		window.set_resizable(True)
		window.set_size_request(890, 584)
	else:
		window.set_resizable(True)
		window.set_size_request(890, 510)
	window.set_position(Gtk.WindowPosition.CENTER),
	browser = webkit.WebView()
	swindow = Gtk.ScrolledWindow()
	window.add(swindow)
	swindow.add(browser)
	window.show_all()
	browser.connect('decide-policy', on_decide_policy)
	
	browser.load_html(frontend, "file://{0}/frontend/".format(app_dir))
	#browser.load_uri("https://google.com")
	settings = browser.get_settings()
	settings.set_property('enable_javascript', True)
	settings.set_property('javascript_can_open_windows_automatically', True)
	settings.set_property('allow_modal_dialogs', True)

	browser.set_settings(settings)
	Gtk.main()


if __name__ == '__main__':
    appname = 'Absolute Control Panel'
    appver = '1.0'
    app_dir = '/usr/share/controlpanel'
    app_icon = "/usr/share/icewm/icons/control.svg"
    fh = 0
    try:
        run_once()
        main()
    except (Exception, AttributeError) as e:
        print("Exiting due to error: {0}".format(e))
        sys.exit(1)
