﻿var activation = window.activation = function(code) {
    return new activation.fn.init(code);
};

activation.fn = activation.prototype = function(code){
    var tks = function(regex, type, callback) {
        this.regex = regex;
        this.type = type;
        var self = this;
        this.callback = callback || function(m, i, tokens) {tokens[tokens.length] = new token(m[0], i, self.type);};
    };
    
    var token = function(code, position, type) {
        this.code = code;
        this.position = position;
        this.type = type;
    };
    
    token.prototype.toString = function() {
        return 'code: '+this.code+'\nposition: '+this.position+'\ntype: '+this.type;
    };
    
    var warningSet = false;
    var Warning = function(warning, details) {
        this.warning = warning;
        this.details = details;
        if ($('#activationErrors').size() < 1) {
            $('#form_button_controls').before('<div id="activationErrors"></div>');
        }
        $('#activationErrors').html(warning+' -- '+details);
        warningSet = true;
    };
    
    var builtins = {
        fieldError: function(id) {
                        new Warning('No field available', 'No field was found with the given id: '+id);
                    },
        field:      function(id) {
                        var f = $('#_'+id);
                        if (f.size() < 1) {
                            f = $('input[name=_'+id+']:checked');
                        }
                        if (f.size() > 0) {
                            return f.val();
                        } else {
                            f = $('input[name=_'+id+']');
                            if (f.size() > 0) {
                                return '';
                            }
                            this.fieldError(id);
                            return false;
                        }
                    },
        getField:   function(id) {
                        var poundId = '#_'+id;
                        var f = $(poundId+','+poundId+'_editcombo_select,'+poundId+'_editcombo_edit');
                        if (f.size() < 1) {
                            f = $('input[name=_'+id+']');
                        }
                        if (f.size() < 1) {
                            this.fieldError(id);
                        }
                        return f;
                    },
        activate:   function(id) {
                        var f = this.getField(id);
                        if (f.size() > 0) {
                            f.each(function() {
                                this.disabled = false;
                            });
                        } else {
                            return false;
                        }
                    },
        deactivate: function(id) {
                        var f = this.getField(id);
                        if (f.size() > 0) {
                            f.each(function() {
                                this.disabled = true;
                            });
                            $('#_'+id+'_error').hide();
                        } else {
                            return false;
                        }
                    },
        hide:       function(id) {
                        var f = this.getField(id);
                        if (f.size() > 0) {
                            f.closest('fieldset').hide();
                        } else {
                            return false;
                        }
                    },
        toggle:     function(id) {
                        var f = this.getField(id);
                        if (f.size() > 0) {
                            f.closest('fieldset').toggle();
                        } else {
                            return false;
                        }
                    },
        show:       function(id) {
                        var f = this.getField(id);
                        if (f.size() > 0) {
                            f.closest('fieldset').show();
                        } else {
                            return false;
                        }
                    },
        /* alert:      function(text) {
                        alert(text);
                    }, */
        fieldupper: function(id) {
                        var field = this.field(id);
                        if (field) {
                            return field.toUpperCase();
                        }
                        return field;
                    },
        fieldlower: function(id) {
                        var field = this.field(id);
                        if (field) {
                            return field.toLowerCase();
                        }
                        return field;
                    }
    };
    
    return {
        init:       function(source) {
                        warningSet = false;
                        this.source = source;
                        return this;
                    },
        
        tokenize:   function(code) {
                        this.tokens = [];
                        var checks = [
                            new tks(/^\s+/i, 'whitespace', function(m,i,tokens){}),
                            new tks(/^"(?:\\.|[^"])*"|^'(?:\\.|[^'])*'/i, 'string'),
                            new tks(/^\d+\.\d*(?:[eE][-+]?\d+)?|^\d+(?:\.\d*)?[eE][-+]?\d+|\.\d+(?:[eE][-+]?\d+)?/, 'number'),
                            new tks(/^0[xX][\da-fA-F]+|^0[0-7]*|^\d+/i, 'number'),
                            new tks(/^([a-zA-Z][a-zA-Z0-9]*)\([^\)]*\)/i, 'function', function(m, i, tokens) {
                                if (m[1].toLowerCase() in {'hide':'','show':'','activate':'','deactivate':'','alert':'','field':'','fieldupper':'','fieldlower':''}) {
                                    tokens[tokens.length] = new token("builtins." + m[0].toLowerCase(), i, this.type);
                                } else {
                                    new Warning('Illegal function call', 'Illegal function call at '+i);
                                    return false;
                                }
                            }),
                            new tks(/^(>=|<=|!=|==|&&|\|\||\(|\)|<|>)/i, 'operator'),
                            new tks(/^if|^endif|^else|^then/i, 'keyword')
                        ];
                        var i = 0;
                        while (i < this.source.length) {
                            var m = null;
                            for (var x = 0; x < checks.length; x++) {
                                if ((m = checks[x].regex.exec(this.source.substring(i)))) {
                                    checks[x].callback(m, i, this.tokens);
                                    break;
                                }
                            }
                            if (m != null) {
                                i += m[0].length;
                            } else {
                                new Warning('Syntax Error', 'Syntax Error at position '+i);
                                return false;
                            }
                        }
                    },
        
        run:        function() {
                        this.tokenize();
                        var i = 0;
                        while(i < this.tokens.length) {
                            var token = this.tokens[i];
                            if (token.code == 'if') {
                                var ifTokens = "";
                                ++i;
                                while(i < this.tokens.length && this.tokens[i].code != 'then') {
                                    if (this.tokens[i].type == 'string' || this.tokens[i].type == 'operator' || this.tokens[i].type == 'number' ||
                                        (this.tokens[i].type == 'function' && this.tokens[i].code.match(/^builtins.field(upper|lower)?\(/i).length > 0)) {
                                        ifTokens += this.tokens[i++].code+" ";
                                    } else {
                                        new Warning('Illegal if statement', 'Illegal types inside an if clause at '+token.position);
                                        return false;
                                    }
                                }
                                if (i == this.tokens.length || this.tokens[i].code != 'then') {
                                    new Warning('If without matching then', 'If without matching then clause at '+token.position);
                                    return false;
                                } else {
                                    ++i;
                                }
                                // Evaluate the if statement, if true, go in, otherwise, go to else or endif
                                if(!eval(ifTokens)) {
                                    while(i < this.tokens.length && this.tokens[i].code != 'else' && this.tokens[i].code != 'endif') {
                                        ++i;
                                    }
                                    if(i < this.tokens.length) {
                                        if (this.tokens[i].code == 'else' && this.tokens[i + 1].code != 'if') {
                                            this.tokens[i].code = 'if 1 then';
                                        } else {
                                            ++i;
                                        }
                                    }
                                }
                            } else if (token.code == 'else') {
                                while (i < this.tokens.length && this.tokens[i].code != 'endif') {
                                    ++i;
                                }
                                if (i < this.tokens.length) {
                                    ++i;
                                }
                            } else if (token.type == 'function') {
                                eval(token.code);
                                if (warningSet) {
                                    return false;
                                };
                                ++i;
                            } else {
                                ++i;
                            };
                        }
                    }
    }
}();

activation.fn.init.prototype = activation.fn;

function run() {
    if ((typeof window.activationCode).toLowerCase() == 'object') {
        for (var i = 0; i < window.activationCode.length; i++) {
            window.activationCode[i].run();
        }
    }
};

function runActivation(skipTimeout) {
    if(!skipTimeout) {
        setTimeout(run, 100);
    } else {
        run();
    };
};

function setupActivation() {
    window.activationCode = new Array();
    $('.activation').each(function() {
        window.activationCode[window.activationCode.length] = activation($(this).text());
    });
};

$(function() {
    setupActivation();
    runActivation();
    $(':input').live('change', function() {
        runActivation();
    });
});
