
function iw_rotor_encode(base64_array, rotor)
{
    var encoded = new Array();
    var runner = 7;

    for (var i = 0; i < base64_array.length; i++) 
    {
        if(base64_array[i] == -1)
        {
            encoded[i] = base64_array[i];
        }
        else 
        {
            encoded[i] = ((base64_array[i] + rotor + runner) % 64);
        }
        runner = (runner + 1) % 64;
    }
    return encoded;
}


function iw_base64_byte_to_base64_char(b)
{
    if(b > 63 || b < 0)
    {
        alert('Invalid base64 byte '+b);
        return '?';
    }
    else 
    {
        return ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
                'abcdefghijklmnopqrstuvwxyz' +
                '0123456789._').charAt(b);
        
    }
}


function iw_base64_character_encode(base64_array)
{
    var encoded = '';
    for(var i = 0; i < base64_array.length; i++) 
    {
        if(base64_array[i] == -1)
        {
            encoded += '=';
        } 
        else
        {
            encoded += iw_base64_byte_to_base64_char(base64_array[i]);
        }
    }
    return encoded;
}


function iw_base64_encode(ascii_array)
{
    var encoded = new Array();
    for(var i = 0; i < ascii_array.length; i += 3)
    {
        var block = 0;
        var slack = ascii_array.length - i -1;
        var end = (slack >= 2) ? 2 : slack;
        for(var block_index = 0; block_index <= end; block_index++)
        {
            var b = ascii_array[i + block_index];
            var neuter = (b < 0) ? b + 256 : b;
            block += neuter << (8 * (2 - block_index));
        } 
        
        for(var j = 0; j < 4; j++)
        { 
            var sixbit = (block >>> (6 * (3 - j))) & 0x3f;
            encoded[(4*i/3) + j] = sixbit;
        }
        if(slack < 1)
        { 
            encoded[(4*i/3) + 2] = -1;
        } 
        if(slack < 2)
        { 
            encoded[(4*i/3) + 3] = -1;
        } 
    } 
    return encoded;
} 

function iw_utf8_encode(string)  
{
         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 iw_ascii_encode(str)
{
    var ascii_encoded = new Array();
    for(var i = 0; i < str.length; i++)
    {
      ascii_encoded[i] = str.charCodeAt(i);
    }
    return ascii_encoded;
}


function iw_checksum_encode(str)
{
    var checksum = 0;
    for(var i = 0; i < str.length; i++)
    {
        checksum += str.charCodeAt(i);
    }
    return iw_base64_byte_to_base64_char(checksum%64) + str;
}


function iw_encode(str, rotor)
{
    var utf8_ascii = iw_utf8_encode(str);
    var ascii = iw_ascii_encode(utf8_ascii);
    var base64 = iw_base64_encode(ascii);
    var rotor_base64 = iw_rotor_encode(base64, rotor);
    var base64_chars = iw_base64_character_encode(rotor_base64);
    var checksummed_rotor_base64_chars = iw_checksum_encode(base64_chars);
    return checksummed_rotor_base64_chars;
}
