#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Captive Portal Helper for MeeGo Harmattan
Python 2.7 + PySide (Qt4) UI
Version 1.0.8
"""

import sys
import os
import json
import subprocess
import threading

reload(sys)
sys.setdefaultencoding('utf-8')

from PySide.QtCore import QObject, QUrl, Slot, Signal, Property, QTimer
from PySide.QtGui import QApplication
from PySide.QtDeclarative import QDeclarativeView

CAPTIVE_HELPER = "/opt/captive-portal/captive_helper.py"


class CaptiveController(QObject):
    detectionComplete = Signal(unicode)
    portalInfoReady = Signal(unicode)
    connectionResult = Signal(unicode)
    pageLoaded = Signal(unicode)
    saveResult = Signal(unicode)
    statusChanged = Signal(unicode)
    loadingChanged = Signal()
    
    def __init__(self, parent=None):
        super(CaptiveController, self).__init__(parent)
        self._loading = False
        self._status = u"Bereit"
        self._portal_url = ""
        self._portal_type = ""
        self._pending = {}
    
    def _get_loading(self):
        return self._loading
    
    loading = Property(bool, _get_loading, notify=loadingChanged)
    
    def _set_loading(self, value):
        if self._loading != value:
            self._loading = value
            self.loadingChanged.emit()
    
    def _run_helper(self, request_id, command, args=None, callback=None):
        self._set_loading(True)
        
        def do_work():
            try:
                cmd = [CAPTIVE_HELPER, command]
                if args:
                    cmd.extend(args)
                
                env = os.environ.copy()
                env['PYTHONIOENCODING'] = 'utf-8'
                
                proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                                       stderr=subprocess.PIPE, env=env)
                out, err = proc.communicate()
                
                if isinstance(out, str):
                    try:
                        out = out.decode('utf-8')
                    except:
                        out = out.decode('iso-8859-1', errors='replace')
                
                self._pending[request_id] = out
            except Exception as e:
                self._pending[request_id] = json.dumps({"error": unicode(e)})
        
        thread = threading.Thread(target=do_work)
        thread.daemon = True
        thread.start()
        
        def check():
            if request_id in self._pending:
                result = self._pending.pop(request_id)
                self._set_loading(False)
                if callback:
                    callback(result)
            else:
                QTimer.singleShot(100, check)
        
        QTimer.singleShot(100, check)
    
    @Slot()
    def detectPortal(self):
        self._status = u"Prüfe Verbindung..."
        self.statusChanged.emit(self._status)
        
        def on_result(result):
            try:
                data = json.loads(result)
                if data.get("internet_available"):
                    self._status = u"✓ Internet verfügbar"
                    self._portal_url = ""
                elif data.get("is_captive"):
                    self._status = u"⚠ Captive Portal erkannt"
                    self._portal_url = data.get("portal_url", "")
                    self._portal_type = data.get("portal_type", "generic")
                else:
                    self._status = u"✗ Keine Verbindung"
                self.statusChanged.emit(self._status)
                self.detectionComplete.emit(result)
            except Exception as e:
                self._status = u"Fehler: %s" % e
                self.statusChanged.emit(self._status)
        
        self._run_helper("detect", "detect", callback=on_result)
    
    @Slot()
    def autoConnect(self):
        self._status = u"Versuche Verbindung..."
        self.statusChanged.emit(self._status)
        
        def on_result(result):
            try:
                data = json.loads(result)
                if data.get("success"):
                    self._status = u"✓ " + data.get("message", "Verbunden!")
                else:
                    self._status = u"✗ " + data.get("error", "Fehlgeschlagen")
                    # Check if page was auto-saved
                    if data.get("saved"):
                        self._status += u"\n(Seite gespeichert)"
                self.statusChanged.emit(self._status)
                self.connectionResult.emit(result)
            except Exception as e:
                self._status = u"Fehler: %s" % e
                self.statusChanged.emit(self._status)
        
        self._run_helper("autoconnect", "autoconnect", callback=on_result)
    
    @Slot()
    def savePortalPage(self):
        """Save the current portal page for analysis"""
        self._status = u"Speichere Portal-Seite..."
        self.statusChanged.emit(self._status)
        
        def on_result(result):
            try:
                data = json.loads(result)
                if data.get("success"):
                    files = data.get("files", [])
                    if files:
                        self._status = u"✓ Gespeichert: " + files[0].get("filename", "")
                    else:
                        self._status = u"✓ " + data.get("message", "Gespeichert")
                else:
                    self._status = u"✗ " + data.get("error", "Fehler")
                self.statusChanged.emit(self._status)
                self.saveResult.emit(result)
            except Exception as e:
                self._status = u"Fehler: %s" % e
                self.statusChanged.emit(self._status)
        
        self._run_helper("save", "save", callback=on_result)
    
    @Slot(unicode)
    def loadPortalPage(self, url):
        if not url:
            url = self._portal_url
        if not url:
            return
        
        self._status = u"Lade Portal..."
        self.statusChanged.emit(self._status)
        
        def on_result(result):
            self._status = u"Portal geladen"
            self.statusChanged.emit(self._status)
            self.portalInfoReady.emit(result)
        
        self._run_helper("info", "info", args=[url], callback=on_result)
    
    @Slot(unicode, unicode)
    def submitForm(self, url, data):
        self._status = u"Sende..."
        self.statusChanged.emit(self._status)
        
        def on_result(result):
            self.detectPortal()
        
        self._run_helper("submit", "submit", args=[url, data], callback=on_result)
    
    @Slot(unicode)
    def fetchUrl(self, url):
        def on_result(result):
            self.pageLoaded.emit(result)
        self._run_helper("fetch", "fetch", args=[url], callback=on_result)
    
    @Slot()
    def tryCdConnect(self):
        """Try ČD / Czech RailJet (Passengera/Icomera) connection method"""
        self._status = u"Versuche ČD Verbindung..."
        self.statusChanged.emit(self._status)

        def on_result(result):
            try:
                data = json.loads(result)
                if data.get("success"):
                    self._status = u"\u2713 " + data.get("message", u"ČD verbunden!")
                else:
                    self._status = u"\u2717 " + data.get("error", u"Fehlgeschlagen")
                self.statusChanged.emit(self._status)
                self.connectionResult.emit(result)
            except Exception as e:
                self._status = u"Fehler: %s" % e
                self.statusChanged.emit(self._status)

        self._run_helper("cd", "cd", callback=on_result)

    @Slot()
    def tryOebbConnect(self):
        """Try ÖBB-specific connection method"""
        self._status = u"Versuche ÖBB Verbindung..."
        self.statusChanged.emit(self._status)
        
        def on_result(result):
            try:
                data = json.loads(result)
                if data.get("success"):
                    self._status = u"✓ " + data.get("message", "ÖBB verbunden!")
                else:
                    self._status = u"✗ " + data.get("error", "Fehlgeschlagen")
                self.statusChanged.emit(self._status)
                self.connectionResult.emit(result)
            except Exception as e:
                self._status = u"Fehler: %s" % e
                self.statusChanged.emit(self._status)
        
        self._run_helper("oebb", "oebb", callback=on_result)
    
    @Slot(result=unicode)
    def getStatus(self):
        return self._status
    
    @Slot(result=unicode)
    def getPortalUrl(self):
        return self._portal_url
    
    @Slot(result=unicode)
    def getPortalType(self):
        return self._portal_type


def main():
    app = QApplication(sys.argv)
    app.setApplicationName("Captive Portal")
    
    controller = CaptiveController()
    
    view = QDeclarativeView()
    view.setResizeMode(QDeclarativeView.SizeRootObjectToView)
    
    context = view.rootContext()
    context.setContextProperty("captive", controller)
    
    qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "qml", "main.qml")
    view.setSource(QUrl.fromLocalFile(qml_path))
    
    view.showFullScreen()
    
    QTimer.singleShot(500, controller.detectPortal)
    
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
