function init()
{
    onPaginateChanged();

    var templates = document.getElementById('templates');
    var gen = document.getElementById('gen');
    templates.style.height = gen.offsetHeight + "px";
}


function getWsdLink( text, style )
{
    function BitWriter()
    {
        // encodes as URL-BASE64
        this.str = "";
        this.partial = 0;
        this.partialSize = 0;
        this.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
        this.addBits = function( bits, size ) 
        {
            this.partial = (this.partial << size) | bits;
            this.partialSize += size;
            while ( this.partialSize >= 6 ) {
                this.str += this.table.charAt((this.partial >> 
                                               (this.partialSize - 6)) & 0x3f);
                this.partialSize -= 6;
            }
        };
        this.finish = function() {
            if ( this.partialSize ) {
                this.str += this.table.charAt( 
                    ( this.partial << ( 6 - this.partialSize ) ) & 0x3f );
                this.partialSize = 0;
                this.partial = 0;
            }
        };
    }

    function encodeBase64(str)
    {
        var writer = new BitWriter();
        for (var n = 0; n < str.length; n++) {
            writer.addBits( str.charCodeAt( n ), 8 );
        }

        writer.finish();

        return writer.str;
    }

    function encodeUtf8(string) {
        // fronm http://www.webtoolkit.info/
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    }

    function encodeNumber(num)
    {
        // encodes a number in only as many bytes as required, 7 bits at a time.
        // bit 8 is used to indicate whether another byte follows.
        if ( num >= 0x3FFF ) {
            return String.fromCharCode( 0x80 | ( (num >> 14) & 0x7f ) ) +
                   String.fromCharCode( 0x80 | ( (num >>  7) & 0x7f ) ) + 
                   String.fromCharCode( num & 0x7f );
        } else if ( num >= 0x7F ) {            
            return String.fromCharCode( 0x80 | ( (num >>  7) & 0x7f ) ) + 
                   String.fromCharCode( num & 0x7f );
        } else {
            return String.fromCharCode( num );
        }
    }

    function encodeLz77( input )
    {
        var MinStringLength = 4;

        var output = "";
        var pos = 0;
        var hash = {};

        // set last pos to just after the last chunk.
        var lastPos = input.length - MinStringLength;

        for ( var i = MinStringLength; i < input.length; i++ ) {
            var subs = input.substr(i-MinStringLength, MinStringLength);
            if ( hash[subs] === undefined ) {
                hash[subs] = [];
            }
            hash[subs].push( i-MinStringLength );
            //document.write("subs[" + subs + "]=" + (pos - MinStringLength) + "<br>");
        }

        // loop until pos reaches the last chunk.
        while (pos < lastPos) {

            // search start is the current position minus the window size, capped
            // at the beginning of the string.
            var matchLength = MinStringLength;
            var foundMatch = false;
            var bestMatch = {distance: 0, length: 0};
            var prefix = input.substr(pos, MinStringLength);
            var matches = hash[prefix];
            
            // loop until the end of the matched region reaches the current
            // position.
            //while ((searchStart + matchLength) < pos) {
            if ( matches !== undefined ) {
                for ( var i = 0; i < matches.length; i++ ) {
                    var searchStart = matches[i];
                    if ( searchStart + matchLength >= pos ) {
                        break;
                    }
                    
                    while( searchStart + matchLength < pos ) {
                        // check if string matches.
                        var isValidMatch = (
                                (input.substr(searchStart, matchLength) == input.substr(pos, matchLength))
                                );
                        if (isValidMatch) {
                            // we found at least one match. try for a larger one.
                            var realMatchLength = matchLength;
                            matchLength++;
                            if (foundMatch && (realMatchLength > bestMatch.length)) {
                                bestMatch.distance = pos - searchStart - realMatchLength;
                                bestMatch.length = realMatchLength;
                            }
                            foundMatch = true;
                        } else {
                            break;
                        }
                    }
                }
            }

            if (bestMatch.length) {
                output += String.fromCharCode( 0 ) + 
                    encodeNumber(bestMatch.distance) +
                    encodeNumber(bestMatch.length);

                pos += bestMatch.length;
            } else {
                if (input.charCodeAt(pos) !== 0) {
                    output += input.charAt(pos);
                } else {
                    output += String.fromCharCode( 0 ) + 
                        String.fromCharCode( 0 );
                }
                pos++;
            }
        }
        return output + input.slice(pos).replace(/\0/g, "\0\0");
    }

    style = "&s=" + style;
    
    var text = encodeBase64( encodeLz77( encodeUtf8( text ) ) );
    var str = "lz=" + text + style;

    if ( str.length < 2048 ) {
        return str;
    }

    return null;
}

function onMoreSpace()
{
    var templates = document.getElementById('templates');
    var gen = document.getElementById('gen');
    gen.rows = 20;
    templates.style.height = gen.offsetHeight + "px";
    hide('linkmorespace');
}

function onPaginateChanged() 
{
    var pform = document.forms['paginateForm'];
    var paginate = pform.paginate.checked;

    pform.paper.disabled = !paginate;
    pform.landscape.disabled = !paginate;

    var controls = document.getElementById("paginateControls");
    if ( paginate ) {
        controls.style.color = "black";
    } else {
        controls.style.color = "gray";
    }
}

function onForum()
{
    window.location = "http://www.websequencediagrams.com/phpbb";
}

function onShowExamples()
{
    window.open("examples.html");
}

function onShowEmbed()
{
    window.open("embedding.html");
}

function hide(id)
{
    var div = document.getElementById(id);
    div.style.display = 'none';
}

function show(id)
{
    var div = document.getElementById(id);
    div.style.display = 'block';
}

function makeAjaxRequest( strUrl, params, fnCallBack, param ) 
{
    var self = this;

    try {
        self.xmlHttpReq = new XMLHttpRequest();
    } catch ( trymicrosoft ) {
        try {
            self.xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(othermicrosoft) {
            try {
                self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
            } catch(failed) {
                self.xmlHttpReq = null;
            }
        }
    }

    self.xmlHttpReq.open('POST', strUrl, true);
    self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    self.xmlHttpReq.onreadystatechange = function() {
        if (self.xmlHttpReq.readyState == 4) {
            if ( fnCallBack ) {
                fnCallBack( self.xmlHttpReq.responseText, param );
            }
        }
    }

    var query = "";
    var first = true;
    for ( var key in params ) {
        if ( !first ) {
            query += '&';
        } 
        first = false;
        query += key + "=" + encodeURIComponent(params[key]);
    }

    self.xmlHttpReq.send(query);
}

var wantedImage = 0;
var ImageNode = null;
var _showPermaLink = false;

function onImageDone( response, param )
{
    if ( wantedImage != param ) {
        // ignore old request
        return;
    }

    var result = eval("("+response+")");
    if ( ImageNode == null ) {
        ImageNode = document.createElement('img');
        document.getElementById("result").appendChild( ImageNode );
    }

    ImageNode.setAttribute("src", result.img)
    document.getElementById("status").innerHTML = "";

    var errors = document.getElementById('errors');
    var str = "";
    for( var i =0; i < result.errors.length; i++ ) {
        str += result.errors[i] + "<br>";
    }

    if ( _showPermaLink ) {
        var entryForm = document.forms['entryForm'];
        var permaLink = getWsdLink( entryForm.message.value, 
                entryForm.stylechoice.value );
        if ( permaLink ) {
            document.getElementById('linkimage').value = 
                "http://www.websequencediagrams.com/cgi-bin/cdraw?" + 
                permaLink;
            document.getElementById('linkpage').value = 
                "http://www.websequencediagrams.com/?" + 
                permaLink;
        } else {
            document.getElementById('linkimage').value = 
                "Diagram too large.";
            document.getElementById('linkpage').value = 
                "Diagram too large.";
        }
    } else {
        show('linkbutton');
    }

    var form = document.forms['paginateForm'];
    
    if ( str.length > 0 ) {
        show('errors');
    }
    errors.innerHTML = str;
}

function onLinkClicked()
{
    var entryForm = document.forms['entryForm'];
    _showPermaLink = true;
    hide('linkbutton');
    show('linkdiv');
    var permaLink = getWsdLink( entryForm.message.value, 
            entryForm.stylechoice.value );
    if ( permaLink ) {
        document.getElementById('linkimage').value = 
            "http://www.websequencediagrams.com/cgi-bin/cdraw?" + 
            permaLink;
        document.getElementById('linkpage').value = 
            "http://www.websequencediagrams.com/?" + 
            permaLink;
    } else {
        document.getElementById('linkimage').value = 
            "Diagram too large.";
        document.getElementById('linkpage').value = 
            "Diagram too large.";
    }
}

function updateImage()
{
    var entryForm = document.forms['entryForm'];
    var paginateForm = document.forms['paginateForm'];

    wantedImage++;

    makeAjaxRequest( 
        "index.php",
        { 
            message: entryForm.message.value, 
            style: entryForm.stylechoice.value,
            scale: entryForm.scalechoice.value,
            paginate: paginateForm.paginate.checked ? "1" : "0",
            paper: paginateForm.paper.value,
            landscape: paginateForm.landscape.checked ? "1" : "0",
            format: 'png'
        },
        onImageDone,
        wantedImage
    );
    document.getElementById("status").innerHTML = "Working...";
}

function onPdfDone(response, param)
{
    var result = eval("("+response+")");
    window.location.href=result.img;
}

function onPdf()
{
    var entryForm = document.forms['entryForm'];
    var paginateForm = document.forms['paginateForm'];

    makeAjaxRequest( 
        "index.php",
        { 
            message: entryForm.message.value, 
            style: entryForm.stylechoice.value,
            paginate: paginateForm.paginate.checked ? "1" : "0",
            paper: paginateForm.paper.value,
            landscape: paginateForm.landscape.checked ? "1" : "0",
            format: 'pdf'
        },
        onPdfDone,
        null
    );
}

function newImage()
{
    if ( ImageNode ) {
        updateImage();
    }
}

// Called by iframe
function addText(text)
{
    textArea = document.getElementById('gen');
    value = textArea.value;
    if ( value.length > 0 && value.substr( value.length-1, 1 ) != "\n" ) {
        value = value + "\n";
    }
    value += text;
    textArea.value = value;

}

