#!/usr/bin/python3
import argparse, sys, os, json, subprocess, platform, inspect
from PyQt5 import Qt, QtWidgets, QtCore

def get_icon_path():
    p = platform.system()

    if p == 'Linux' and sys.argv and sys.argv[0].startswith(sys.prefix):
        # Porcupine is installed systemwide in Linux
        prefix = os.path.join(sys.prefix, 'share/pixmaps')

    elif getattr(sys, 'frozen', False):
        # Check if app is "frozen"
        # https://pythonhosted.org/PyInstaller/#run-time-information
        if p == 'Darwin':
            prefix = os.path.join(sys._MEIPASS, 'share')
        elif p == 'Windows':
            prefix = os.path.join(os.path.dirname(sys.executable), 'share')

    else:
        # Look for share directory relative to python file
        prefix = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))), 'share')

    return os.path.join(prefix, "porcupine.png")

def validate_url(url):
    return (url.lower().startswith('http://') or url.lower().startswith('https://'))

def delay(app, milliseconds):
    time = QtCore.QTime.currentTime().addMSecs(milliseconds)
    while (QtCore.QTime.currentTime() < time):
        app.processEvents()

class Settings(object):
    def __init__(self):
        p = platform.system()
        if p == 'Windows':
            appdata = os.environ['APPDATA']
            self.path = '{}\\Porcupine\\porcupine.json'.format(appdata)
        elif p == 'Darwin':
            self.path = os.path.expanduser('~/Library/Application Support/Porcupine/porcupine.json')
        else:
            self.path = os.path.expanduser('~/.config/porcupine.json')

    def load(self):
        use_default = False
        if os.path.exists(self.path):
            try:
                settings = json.load(open(self.path, 'r'))
            except:
                use_default = True
        else:
            use_default = True

        if use_default:
            settings = {
                'action': 'clipboard',
                'cmd': ''
            }

        return settings

    def save(self, action, cmd):
        settings = {
            'action': action,
            'cmd': cmd
        }

        try:
            os.makedirs(os.path.dirname(self.path))
        except:
            pass

        json.dump(settings, open(self.path, 'w'))

class PorcupineSettingsWindow(QtWidgets.QMainWindow):
    def __init__(self, app, settings):
        super(PorcupineSettingsWindow, self).__init__()
        self.app = app
        self.settings = settings
        self.setWindowTitle('Porcupine')
        self.setWindowIcon(Qt.QIcon(get_icon_path()))

        # Load the settings
        s = self.settings.load()

        # Build the GUI
        label = QtWidgets.QLabel('What should Porcupine do with the URL?')
        self.radio_clipboard = QtWidgets.QRadioButton('Copy it to the clipboard')
        self.radio_clipboard.toggled.connect(self.toggle)
        self.radio_command = QtWidgets.QRadioButton('Run command with the URL')
        self.radio_command.toggled.connect(self.toggle)
        if s['action'] == 'clipboard':
            self.radio_clipboard.setChecked(True)
            self.radio_command.setChecked(False)
        else:
            self.radio_clipboard.setChecked(False)
            self.radio_command.setChecked(True)
        self.edit_command = QtWidgets.QLineEdit()
        self.edit_command.setPlaceholderText('for example: qvm-open-in-dvm %U')
        self.edit_command.setText(s['cmd'])
        button_save = QtWidgets.QPushButton("Save Settings")
        button_save.clicked.connect(self.save_settings)

        self.update_ui()

        # Set the layout
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(label)
        layout.addWidget(self.radio_clipboard)
        layout.addWidget(self.radio_command)
        layout.addWidget(self.edit_command)
        layout.addStretch()
        layout.addWidget(button_save)
        central_widget = QtWidgets.QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)
        self.show()

    def toggle(self):
        self.update_ui()

    def update_ui(self):
        # Only update the UI if it has been built
        if hasattr(self, 'radio_clipboard') and hasattr(self, 'radio_command') and hasattr(self, 'edit_command'):
            if self.radio_clipboard.isChecked():
                self.edit_command.hide()
            if self.radio_command.isChecked():
                self.edit_command.show()

    def save_settings(self):
        if self.radio_clipboard.isChecked():
            action = 'clipboard'
        else:
            action = 'command'
        cmd = self.edit_command.text()

        self.settings.save(action, cmd)
        self.close()

def main():
    # Parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('url', metavar='url', nargs='?', help='URL to open')
    args = parser.parse_args()

    # Create the settings object
    settings = Settings()

    # Start the Qt application
    app = QtWidgets.QApplication(sys.argv)

    if args.url is None:
        # No arguments, open the settings dialog
        settings_window = PorcupineSettingsWindow(app, settings)

    else:
        # Start the system tray
        systray = Qt.QSystemTrayIcon(Qt.QIcon(get_icon_path()))
        systray.show()
        delay(app, 20)

        # Validate it as a URL
        url = sys.argv[1]

        if validate_url(url):
            # Load settings
            s = settings.load()

            if s['action'] == 'clipboard':
                # Copy to clipboard
                clipboard = app.clipboard()
                clipboard.setText(url)
                systray.showMessage("Copied address to clipboard", url)
            else:
                # Launch subprocess
                cmd = s['cmd'].split()
                cmd = [url if x=='%U' else x for x in cmd]
                try:
                    subprocess.call(cmd)
                except:
                    systray.showMessage("Porcupine", "Error running command: {}".format(s['cmd']))
        else:
            systray.showMessage("Porcupine", "{} does not appear to be a URL".format(url))

        # Quit after a few seconds
        def quit():
            systray.hide()
            app.quit()
        timer = QtCore.QTimer()
        timer.timeout.connect(quit)
        timer.start(4000)

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
