import wx
import wx.html

SENTINEL = object()

def GetParam(tag, param, default=SENTINEL):
    """ Convenience function for accessing tag parameters"""
    if tag.HasParam(param):
        return tag.GetParam(param)
    else:
        if default == SENTINEL:
            raise KeyError
        else:
            return default


FormSubmitEventType = wx.NewEventType()

EVT_FORM_SUBMIT = wx.PyEventBinder(FormSubmitEventType)

class FormSubmitEvent(wx.PyEvent):
    """
        Event indication a form was submitted.
        action is the action attribute of the form
        method is "GET" or "POST"
        args is a dict of form arguments
    """
    def __init__(self, action, method, args):
        wx.PyEvent.__init__(self)
        self.SetEventType(FormSubmitEventType)
        self.action = action
        self.method = method
        self.args = args
        
    
class FormControlMixin(object):
    def __init__(self, form, tag):
        if not form:
            return
        self.__form = form
        self.name = GetParam(tag, "NAME", None)
        form.fields.append(self)
        self.Bind(wx.EVT_TEXT_ENTER, self.__OnEnter)
        self.Bind(wx.EVT_BUTTON, self.__OnClick)
    def __OnEnter(self, evt):
        self.__form.submit()
    def __OnClick(self, evt):
        self.__form.submit()
    
    
class HTMLForm(object):
    def __init__(self, tag, container):
        self.container = container
        self.fields = []
        self.action = GetParam(tag, "ACTION", default=None)
        self.method = GetParam(tag, "METHOD", "GET")
        if self.method not in ("GET", "POST"):
            self.method = "GET"
    def submit(self):
        evt = FormSubmitEvent(self.action, self.method, self.createArguments())
        self.container.ProcessEvent(evt)
        
    def createArguments(self):
        args = {}
        for field in self.fields:
            if field.name:
                args[field.name] = field.GetValue()
        return args

class SubmitButton(wx.Button, FormControlMixin):
    def __init__(self, parent, form, tag, *args, **kwargs):
        wx.Button.__init__(self, parent, *args, **kwargs)
        FormControlMixin.__init__(self, form, tag)
        if tag.HasParam("value"):
            self.SetLabel(tag.GetParam("value"))
        else:
            self.SetLabel("Submit Query")
    def GetValue(self):
        return self.GetLabel()
        

class TextInput(wx.TextCtrl, FormControlMixin):
    def __init__(self, parent, form, tag, *args, **kwargs):
        if form:
            style = wx.TE_PROCESS_ENTER
            if "style" in kwargs:
                kwargs["style"] = kwargs["style"] | style
            else:
                kwargs["style"] = style
        wx.TextCtrl.__init__(self, parent, *args, **kwargs)
        FormControlMixin.__init__(self, form, tag)
        #todo - should be a weakref?
        self.SetValue(GetParam(tag, "VALUE", ''))
            
            
class PasswordInput(TextInput):
    def __init__(self, parent, form, tag):
        TextInput.__init__(self, parent, form, tag, style=wx.TE_PASSWORD)
        

class FormTagHandler(wx.html.HtmlWinTagHandler):
    typeregister = {
        "text":TextInput,
        "password": PasswordInput,
        "submit": SubmitButton,
    }
    typeregister.setdefault(TextInput)
    def __init__(self):
        self.form = None
        wx.html.HtmlWinTagHandler.__init__(self)
    
    def GetSupportedTags(self):
        return "FORM,INPUT,TEXTAREA"
        
    def HandleTag(self, tag):
        try:
            handler = getattr(self, "Handle"+tag.GetName().upper())
            return handler(tag)
        except:
            import traceback
            traceback.print_exc()
        
    def HandleFORM(self, tag):
        print "handle form"
        self.form = HTMLForm(tag, self.GetParser().GetWindowInterface().GetHTMLWindow())
        self.cell = self.GetParser().OpenContainer()
        self.ParseInner(tag)
        self.GetParser().CloseContainer()
        self.form = None
        return True
    
    def HandleINPUT(self, tag):
        print "handle input"
        parent = self.GetParser().GetWindowInterface().GetHTMLWindow()
        if tag.HasParam("type"):
            ttype = tag.GetParam("type")
        else:
            ttype = "text"
        klass = self.typeregister[ttype]
        object = klass(parent, self.form, tag)
        #attribute supports
        cell = self.GetParser().GetContainer()
        cell.InsertCell(
            wx.html.HtmlWidgetCell(object)
        )
        
wx.html.HtmlWinParser_AddTagHandler(FormTagHandler)


if __name__ == '__main__':
    app = wx.App(False)
    f = wx.Frame(None)
    
    html = wx.html.HtmlWindow(f)
    html.LoadFile(r"C:\htmlt.html")
    
    def OnFormSubmit(evt):
        print "Submitting to %s via %s with args %s"% (evt.action, evt.method, evt.args)
    html.Bind(EVT_FORM_SUBMIT, OnFormSubmit)
    f.Show()
    app.MainLoop()
