﻿// JScript File

function add_output(text,divid)
{
    divid.innerHTML = divid.innerHTML + text;
    divid.visible = false;
}

function is_num_digit(ch)
{
    return ( (ch == '0') || (ch == '1') || (ch == '2') || (ch == '3') ||
             (ch == '4') || (ch == '5') || (ch == '6') || (ch == '7') ||
             (ch == '8') || (ch == '9') );
}

function is_alphabetic_char(ch)
{
    return ( (ch >= 'A') && (ch <= 'Z') );
}

function decode_token(token,divid)
{
    
    // Check if token is "calm wind"
    if(token == "00000KT")
    {
        add_output("Calm wind<BR>",divid);
        return;
    }

    // Check if token is Wind indication
    var reWindKT  = /^(\d{3}|VRB)(\d{2,3})(G\d{2,3})?(KT|MPS|KMH)$/;
    if(reWindKT.test(token))
    {
        // Wind token: dddss(s){Gss(s)}KT -- ddd is true direction, ss(s) speed in knots
        var myArray = reWindKT.exec(token);
        var units = myArray[4];
        add_output("Wind: ",divid);
        if(myArray[1]=="VRB")
          add_output(" Variable in direction",divid);
        else
          add_output(" True direction = " + myArray[1] + " degrees",divid);
        add_output(", Speed: " + parseInt(myArray[2],10),divid);
        if(units=="KT") add_output(" knots",divid);
        else if(units=="KMH") add_output(" km/h",divid);
        else if(units=="MPS") add_output(" m/s",divid);
        if(myArray[3] != null)
        {
            // I don't have the time nor the energy to investigate why
            // MSIE and Firefox behave differently with respect to an
            // omitted regular subexpression. Hence this quick hack to
            // detect if myArray[3] is not a number.
            if (myArray[3]!="")
            {
                add_output(", with Gusts of maximum speed " + parseInt(myArray[3].substr(1,myArray[3].length),10),divid);
                if(units=="KT") add_output(" knots",divid);
                else if(units=="KMH") add_output(" km/h",divid);
                else if(units=="MPS") add_output(" m/s",divid);
             }
        }

        add_output("<BR>",divid);  return;
    }


    // Check if token is "variable wind direction"
    var reVariableWind = /^(\d{3})V(\d{3})$/;
    if(reVariableWind.test(token))
    {
        // Variable wind direction: aaaVbbb, aaa and bbb are directions in clockwise order
        add_output("Wind direction is variable between "+token.substr(0,3)+" and "+token.substr(4,3)+"<BR>",divid);
        return;
    }


    // Check if token is visibility
    var reVis = /^(\d{4})(N|S)?(E|W)?$/;
    if(reVis.test(token))
    {
        var myArray = reVis.exec(token);
        add_output("Visibility: ",divid);
        if(myArray[1]=="9999")
          add_output("10 km or more",divid);
        else if (myArray[1]=="0000")
          add_output("less than 50 m",divid);
        else
          add_output(parseInt(myArray[1],10) + " m",divid);

	var dir = "";
        if(typeof myArray[2] != "undefined")
        {
          dir=dir + myArray[2];
        }
        if(typeof myArray[3] != "undefined")
        {
          dir=dir + myArray[3];
        }
        if(dir != "")
        {
          add_output(" direction ",divid);
          if(dir=="N") add_output("North",divid);
          else if(dir=="NE") add_output("North East",divid);
          else if(dir=="E") add_output("East",divid);
          else if(dir=="SE") add_output("South East",divid);
          else if(dir=="S") add_output("South",divid);
          else if(dir=="SW") add_output("South West",divid);
          else if(dir=="W") add_output("West",divid);
          else if(dir=="NW") add_output("North West",divid);
        }
        add_output("<BR>",divid); return;
    }

    // Check if token is Statute-Miles visibility
     var reVisUS = /(SM)$/;
     if(reVisUS.test(token))
     {
      add_output("Visibility: ",divid);
      var myVisArray = token.split("S");
      add_output(myVisArray[0],divid);
      add_output(" Statute Miles<BR>",divid);
    }
     

    // Check if token is QNH indication in mmHg or hPa
    var reQNHhPa = /Q\d{3,4}/;
    if(reQNHhPa.test(token))
    {
        // QNH token: Qpppp -- pppp is pressure hPa 
        add_output("QNH (Sea-level pressure): ",divid);
        add_output(parseInt(token.substr(1,4),10) + " hPa",divid); 
        add_output("<BR>",divid);  return;
    }

    // Check if token is QNH indication in mmHg: Annnn
    var reINHg = /A\d{4}/;
    if(reINHg.test(token))
    {
        add_output("QNH: ",divid);
        add_output(token.substr(1,2) + "." + token.substr(3,4) + " inHg",divid);
        add_output("<BR>",divid);  return;
    } 

    // Check if token is runway visual range (RVR) indication
    var reRVR = /^R(\d{2})(R|C|L)?\/(M|P)?(\d{4})(V\d{4})?(U|D|N)?$/;
    if(reRVR.test(token))
    {
        var myArray = reRVR.exec(token);
        add_output("Runway ",divid);
        add_output(myArray[1],divid);
        if(typeof myArray[2] != "undefined")
        {
          if(myArray[2]=="L") add_output(" Left",divid);
          else if(myArray[2]=="R") add_output(" Right",divid);
          else if(myArray[2]=="C") add_output(" Central",divid);
        }
        add_output(", touchdown zone visual range is ",divid);
        if(typeof myArray[5] != "undefined")
        {
            // Variable range
            add_output("variable from a minimum of ",divid);
            if(myArray[3]=="P") add_output("more than ",divid);
            else if(myArray[3]=="M") add_output("less than ",divid);
            add_output(myArray[4],divid);
            add_output(" meters",divid);
            add_output(" until a maximum of "+myArray[5].substr(1,myArray[5].length)+" meters",divid);
        }
        else
        {
          // Single value
          if( (typeof myArray[3] != "undefined") &&
              (typeof myArray[4] != "undefined")    )
          {
            if(myArray[3]=="P") add_output("more than ",divid);
            else if(myArray[3]=="M") add_output("less than ",divid);
            add_output(myArray[4],divid);
            add_output(" meters",divid);
          }
        }
        if( (myArray.length > 5) && (typeof myArray[6] != "undefined") )
        {
          if(myArray[6]=="U") add_output(", and increasing",divid);
          else if(myArray[6]=="D") add_output(", and decreasing",divid);
        }
        add_output("<BR>",divid);
        return;
    }

 
    // Check if token is CAVOK
    if(token == "CAVOK")
    {
        add_output("CAVOK conditions: Visibility 10 km or more,<BR>    no cloud below 5.000 feet or below the MSA (whichever is greater), <BR>    no cumulonimbus, and no significant weather fenomena in<BR>    the aerodrome or its vicinity<BR>",divid);
        return;
    }


    // Check if token is NOSIG
    if(token == "NOSIG")
    {
        add_output("No significant changes expected in the near future<BR>",divid);
        return;
    }


    // Check if token is a present weather code - The regular expression is a bit
    // long, because several precipitation types can be joined in a token, and I
    // don't see a better way to get all the codes.
    var reWX = /^(\-|\+)?(VC)?(MI|BC|BL|SH|TS|FZ|PR)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS|BR|FG|FU|VA|DU|SA|HZ|PO|SQ|FC|SS|DS)$/;
    if(reWX.test(token))
    {
        add_output("Weather: ",divid);
        var myArray = reWX.exec(token);
        for(var i=1;i<myArray.length; i++)
        {
            if(myArray[i] == "-") add_output("Light ",divid);
            if(myArray[i] == "+") add_output("Strong ",divid);
            if(myArray[i] == "VC") add_output("In the vicinity, ",divid);
            if(myArray[i] == "MI") add_output("Shallow ",divid);
            if(myArray[i] == "BC") add_output("Patches of ",divid);
            if(myArray[i] == "SH") add_output("Showers of ",divid);
            if(myArray[i] == "TS") add_output("Thunderstorms ",divid);
            if(myArray[i] == "FZ") add_output("Freezing (or super-cooled) ",divid);
            if(myArray[i] == "PR") add_output("Partial ",divid);
            if(myArray[i] == "DZ") add_output("Drizzle ",divid);
            if(myArray[i] == "RA") add_output("Rain ",divid);
            if(myArray[i] == "SN") add_output("Snow ",divid);
            if(myArray[i] == "SG") add_output("Snow grains ",divid);
            if(myArray[i] == "IC") add_output("Ice Crystals ",divid);
            if(myArray[i] == "PL") add_output("Ice Pellets ",divid);
            if(myArray[i] == "GR") add_output("Hail ",divid);
            if(myArray[i] == "GS") add_output("Small hail (< 5 mm diameter) and/or snow pellets ",divid);
            if(myArray[i] == "BR") add_output("Mist ",divid);
            if(myArray[i] == "FG") add_output("Fog ",divid);
            if(myArray[i] == "FU") add_output("Smoke ",divid);
            if(myArray[i] == "VA") add_output("Volcanic Ash ",divid);
            if(myArray[i] == "DU") add_output("Widespread dust ",divid);
            if(myArray[i] == "SA") add_output("Sand ",divid);
            if(myArray[i] == "HZ") add_output("Haze ",divid);
            if(myArray[i] == "PO") add_output("Dust/Sand whirls ",divid);
            if(myArray[i] == "SQ") add_output("Squall ",divid);
            if(myArray[i] == "FC") add_output("Funnel clouds ",divid);
            if(myArray[i] == "SS") add_output("Sandstorm ",divid);
            if(myArray[i] == "DS") add_output("Duststorm ",divid);
        }
        add_output("<BR>",divid);  return;
    }


    // Check if token is recent weather observation
    var reREWX = /^RE(\-|\+)?(VC)?(MI|BC|BL|SH|TS|FZ|PR)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS)?(DZ|RA|SN|SG|IC|PL|GR|GS|BR|FG|FU|VA|DU|SA|HZ|PO|SQ|FC|SS|DS)?$/;
    if(reREWX.test(token))
    {
        add_output("Since the previous observation (but not at present), the following<BR>meteorological phenomena were observed: ",divid);
        var myArray = reREWX.exec(token);
        for(var i=1;i<myArray.length; i++)
        {
            if(myArray[i] == "-") add_output("Light ",divid);
            if(myArray[i] == "+") add_output("Strong ",divid);
            if(myArray[i] == "VC") add_output("In the vicinity, ",divid);
            if(myArray[i] == "MI") add_output("Shallow ",divid);
            if(myArray[i] == "BC") add_output("Patches of ",divid);
            if(myArray[i] == "SH") add_output("Showers of ",divid);
            if(myArray[i] == "TS") add_output("Thunderstorms ",divid);
            if(myArray[i] == "FZ") add_output("Freezing (or super-cooled) ",divid);
            if(myArray[i] == "PR") add_output("Partial ",divid);
            if(myArray[i] == "DZ") add_output("Drizzle ",divid);
            if(myArray[i] == "RA") add_output("Rain ",divid);
            if(myArray[i] == "SN") add_output("Snow ",divid);
            if(myArray[i] == "SG") add_output("Snow grains ",divid);
            if(myArray[i] == "IC") add_output("Ice Crystals ",divid);
            if(myArray[i] == "PL") add_output("Ice Pellets ",divid);
            if(myArray[i] == "GR") add_output("Hail ",divid);
            if(myArray[i] == "GS") add_output("Small hail (< 5 mm diameter) and/or snow pellets ",divid);
            if(myArray[i] == "BR") add_output("Mist ",divid);
            if(myArray[i] == "FG") add_output("Fog ",divid);
            if(myArray[i] == "FU") add_output("Smoke ",divid);
            if(myArray[i] == "VA") add_output("Volcanic Ash ",divid);
            if(myArray[i] == "DU") add_output("Widespread dust ",divid);
            if(myArray[i] == "SA") add_output("Sand ",divid);
            if(myArray[i] == "HZ") add_output("Haze ",divid);
            if(myArray[i] == "PO") add_output("Dust/Sand whirls ",divid);
            if(myArray[i] == "SQ") add_output("Squall ",divid);
            if(myArray[i] == "FC") add_output("Funnel clouds ",divid);
            if(myArray[i] == "SS") add_output("Sandstorm ",divid);
            if(myArray[i] == "DS") add_output("Duststorm ",divid);
        }
        add_output("<BR>",divid); return;
    }


    // Check if token is temperature / dewpoint pair
    var reTempDew = /^(M?\d\d|\/\/)\/(M?\d\d)?$/;
    if(reTempDew.test(token))
    {
        var myArray = reTempDew.exec(token);

        if(myArray[1].charAt(0)=='M')
          add_output("Temperature: -" + myArray[1].substr(1,2) + " degrees Celsius<BR>",divid);
        else
          add_output("Temperature: " + myArray[1].substr(0,2) + " degrees Celsius<BR>",divid);

        if(myArray[2]!="")
        {
          if(myArray[2].charAt(0)=='M')
            add_output("Dewpoint: -" + myArray[2].substr(1,2) + " degrees Celsius<BR>",divid);
          else
            add_output("Dewpoint: " + myArray[2].substr(0,2) + " degrees Celsius<BR>",divid);
        }

        return;
    }


    // Check if token is "sky clear" indication
    if(token=="SKC")
    {
        add_output("Clear sky<BR>",divid);
        return;
    }


    // Check if token is "vertical visibility" indication
    var reVV = /^VV(\d{3}|\/{3})$/;
    if(reVV.test(token))
    {
        // VVddd -- ddd is vertical distance, or /// if unspecified
        var myArray = reVV.exec(token);
        add_output("Sky is obscured -- vertical visibility",divid);
        if(myArray[1] == "///")
          add_output(" cannot be assessed<BR>",divid);
        else
          add_output(": " + (100*parseInt(myArray[1],10)) + " feet<BR>",divid);

        return;
    }


    // Check if token is cloud indication
    var reCloud = /^(FEW|SCT|BKN|OVC)(\d{3})(CB|TCU)?$/;
    if(reCloud.test(token))
    {
    
        // Clouds: aaadddkk -- aaa indicates amount of sky covered, ddd distance over
        //                     aerodrome level, and kk the type of cloud.
        var myArray = reCloud.exec(token);
        add_output("Clouds: ",divid);
        if(myArray[1] == "FEW") add_output("A few ",divid);
        else if(myArray[1] == "SCT") add_output("Scattered ",divid);
        else if(myArray[1] == "BKN") add_output("Broken sky ",divid);
        else if(myArray[1] == "OVC") add_output("Overcast sky ",divid);
       
        add_output(", at " + (100*parseInt(myArray[2],10)) + " feet above aerodrome level",divid);

        if(myArray[3] == "CB") add_output(", cumulonimbus",divid);
        else if(myArray[3] == "TCU") add_output(", towering cumulus",divid);

        add_output("<BR>",divid); 
        return; 
    }


    // Check if token is part of a wind-shear indication
    var reRWY = /^RWY(\d{2})(L|C|R)?$/;
    if(token=="WS")       { add_output("There is wind-shear in ",divid); return; }
    else if(token=="ALL") { add_output("all ",divid); return; }
    else if(token=="RWY") { add_output("runways<BR>",divid); return; }
    else if (reRWY.test(token))
    {
        var myArray = reRWY.exec(token);
        add_output("runway "+myArray[1]);
        if(myArray[2]=="L")      add_output(" Left",divid);
        else if(myArray[2]=="C") add_output(" Central",divid);
        else if(myArray[2]=="R") add_output(" Right",divid);
        add_output("<BR>",divid);
        return;
    }
    

    // Check if token is no-significant-weather indication
    if(token=="NSW")
    {
        add_output("No significant weather phenomena are observed at present<BR>",divid);
        return;
    }


    // Check if token is no-significant-clouds indication
    if(token=="NSC")
    {
        add_output("No significant clouds are observed below 5000 feet or below the minimum sector altitude (whichever is higher)<BR>",divid);
        return;
    }


    // Check if token is part of trend indication
    if(token=="BECMG")
    {
        add_output("The following weather phenomena are expected to arise soon:<BR>",divid);
        return;
    }
    if(token=="TEMPO")
    {
        add_output("The following weather phenomena are expected to arise temporarily:<BR>",divid);
        return;
    }
    var reFM = /^FM(\d{2})(\d{2})Z?$/;
    if(reFM.test(token))
    {
        var myArray = reFM.exec(token);
        add_output("    From "+myArray[1]+":"+myArray[2]+" UTC, ",divid);
        return;
    }
    var reTL = /^TL(\d{2})(\d{2})Z?$/;
    if(reTL.test(token))
    {
        var myArray = reTL.exec(token);
        add_output("Until "+myArray[1]+":"+myArray[2]+" UTC, ",divid);
        return;
    }
    var reAT = /^AT(\d{2})(\d{2})Z?$/;
    if(reAT.test(token))
    {
        var myArray = reAT.exec(token);
        add_output("At "+myArray[1]+":"+myArray[2]+" UTC, ",divid);
        return;
    }


    // Check if item is runway state group
    var reRSG = /^(\d\d)(\d|C|\/)(\d|L|\/)(\d\d|RD|\/)(\d\d)$/;
    if(reRSG.test(token))
    {
        var myArray = reRSG.exec(token);
        add_output("Runway state:<BR>",divid);

        // Runway designator (first 2 digits)
        var r = parseInt(myArray[1],10);
        if(r < 50) add_output("    Runway " + myArray[1] + " (or "+myArray[1]+" Left): ",divid);
        else if(r < 88) add_output("    Runway " + (r-50) + " Right: ",divid);
        else if(r == 88) add_output("    All runways: ",divid);

        // Check if "CLRD" occurs in digits 3-6
        if(token.substr(2,4)=="CLRD") add_output("clear, ",divid);
        else
        {
          // Runway deposits (third digit)
          if(myArray[2]=="0") add_output("clear and dry, ",divid);
          else if(myArray[2]=="1") add_output("damp, ",divid);
          else if(myArray[2]=="2") add_output("wet or water patches, ",divid);
          else if(myArray[2]=="3") add_output("rime or frost covered, ",divid);
          else if(myArray[2]=="4") add_output("dry snow, ",divid);
          else if(myArray[2]=="5") add_output("wet snow, ",divid);
          else if(myArray[2]=="6") add_output("slush, ",divid);
          else if(myArray[2]=="7") add_output("ice, ",divid);
          else if(myArray[2]=="8") add_output("compacted or rolled snow, ",divid);
          else if(myArray[2]=="9") add_output("frozen ruts or ridges, ",divid);
          else if(myArray[2]=="/") add_output("deposit not reported, ",divid);

          // Extent of runway contamination (fourth digit)
          if(myArray[3]=="1") add_output("contamination 10% or less, ",divid);
          else if(myArray[3]=="2") add_output("contamination 11% to 25%, ",divid);
          else if(myArray[3]=="5") add_output("contamination 26% to 50%, ",divid);
          else if(myArray[3]=="9") add_output("contamination 51% to 100%, ",divid);
          else if(myArray[3]=="/") add_output("contamination not reported, ",divid);

          // Depth of deposit (fifth and sixth digits)
          if(myArray[4]=="//") add_output("depth of deposit not reported, ",divid);
          else
          {
              var d = parseInt(myArray[4],10);
              if(d == 0) add_output("deposit less than 1 mm deep, ",divid);
              else if ((d >  0) && (d < 91)) add_output("deposit is "+d+" mm deep, ",divid);
              else if (d == 92) add_output("deposit is 10 cm deep, ",divid);
              else if (d == 93) add_output("deposit is 15 cm deep, ",divid);
              else if (d == 94) add_output("deposit is 20 cm deep, ",divid);
              else if (d == 95) add_output("deposit is 25 cm deep, ",divid);
              else if (d == 96) add_output("deposit is 30 cm deep, ",divid);
              else if (d == 97) add_output("deposit is 35 cm deep, ",divid);
              else if (d == 98) add_output("deposit is 40 cm or more deep, ",divid);
              else if (d == 99) add_output("runway(s) is/are non-operational due to snow, slush, ice, large drifts or runway clearance, but depth of deposit is not reported, ",divid);
          }
        }

        // Friction coefficient or braking action (seventh and eighth digit)
        if(myArray[5]=="//") add_output("braking action not reported",divid);
        else
        {
            var b = parseInt(myArray[5],10);
            if(b<91) add_output("friction coefficient 0."+myArray[5],divid);
            else
            {
                 if(b == 91) add_output("braking action is poor",divid);
                 else if(b == 92) add_output("braking action is medium/poor",divid);
                 else if(b == 93) add_output("braking action is medium",divid);
                 else if(b == 94) add_output("braking action is medium/good",divid);
                 else if(b == 95) add_output("braking action is good",divid);
                 else if(b == 99) add_output("braking action figures are unreliable",divid);
            }
        }
        add_output("<BR>",divid); return;
    } 

    if(token=="SNOCLO")
    {
        add_output("Aerodrome is closed due to snow on runways<BR>",divid);
        return;
    }

    // Check if item is sea status indication
    reSea = /^W(M)?(\d\d)\/S(\d)/;
    if(reSea.test(token))
    {
        var myArray = reSea.exec(token);
        add_output("Sea surface temperature: ",divid);
        if(myArray[1]=="M")
            add_output("-",divid);
        add_output(parseInt(myArray[2],10) + " degrees Celsius<BR>",divid);

        add_output("Sea waves have height: ",divid);
        if(myArray[3]=="0") add_output("0 m (calm)<BR>",divid);
        else if(myArray[3]=="1") add_output("0-0,1 m<BR>",divid);
        else if(myArray[3]=="2") add_output("0,1-0,5 m<BR>",divid);
        else if(myArray[3]=="3") add_output("0,5-1,25 m<BR>",divid);
        else if(myArray[3]=="4") add_output("1,25-2,5 m<BR>",divid);
        else if(myArray[3]=="5") add_output("2,5-4 m<BR>",divid);
        else if(myArray[3]=="6") add_output("4-6 m<BR>",divid);
        else if(myArray[3]=="7") add_output("6-9 m<BR>",divid);
        else if(myArray[3]=="8") add_output("9-14 m<BR>",divid);
        else if(myArray[3]=="9") add_output("more than 14 m (huge!)<BR>",divid);
        return;
    }
}


function metar_decode(text,divid)
{
//alert(divid);
    //alert("HERE" + text);
    text = text.replace("TAF ","");
    //document.encoded.decreport.value = "";
    divid.innerHTML = "<b>Metar Decoded</b><BR>";
    
   //yPos = window.event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
   //xPos = window.event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;

    //divid.style.left=xPos;
    //divid.style.top=yPos;

    //weatherSpan.style.left = window.event.pageX + "px;" ;
    //weatherSpan.style.top = window.event.pageY + "px;";

    // Join newline-separated pieces...
//    var newlineJoined = text.replace(/<BR>/, " ",divid);
    var newlineJoined = text.replace(/(\x0d\x0a)|\x0D|\x0A/, " ");

    // An '=' finishes the report
    var equalPosition = newlineJoined.indexOf("=");
    if (equalPosition > -1)
    {
        alert("End of a METAR report is indicated by '='. We only decode until the first '='!!");
        newlineJoined = newlineJoined.substr(0,equalPosition);
    }
    
    var arrayOfTokens;
    arrayOfTokens = newlineJoined.split(" ");
    var numToken = 0;

    // Check if initial token is non-METAR date
    var reDate = /^\d\d\d\d\/\d\d\/\d\d/;
    if (reDate.test(arrayOfTokens[numToken]))
        numToken++;

    // Check if initial token is non-METAR time
    var reTime = /^\d\d:\d\d/;
    if (reTime.test(arrayOfTokens[numToken]))
        numToken++;

    // Check if initial token indicates type of report
    if(arrayOfTokens[numToken] == "METAR")
        numToken++;
    else if(arrayOfTokens[numToken] == "SPECI")
    {
        add_output("Report is a SPECIAL report<BR>",divid);
        numToken++;
    }

    // Parse location token
    if (arrayOfTokens[numToken].length == 4)
    {
        add_output("Location: " + arrayOfTokens[numToken] + "<BR>",divid);
        numToken++;
    }
    else
    {
        add_output("Invalid report: malformed location token '" + arrayOfTokens[numToken] + "' <BR>-- it should be 4 characters long!",divid);
        return;
    }


    // Parse date-time token -- we allow time specifications without final 'Z'
    if ( (
           ( (arrayOfTokens[numToken].length == 7) &&
             (arrayOfTokens[numToken].charAt(6) == 'Z') ) ||
           ( arrayOfTokens[numToken].length == 6 )
         ) &&
         is_num_digit(arrayOfTokens[numToken].charAt(0)) &&
         is_num_digit(arrayOfTokens[numToken].charAt(1)) &&
         is_num_digit(arrayOfTokens[numToken].charAt(2)) &&
         is_num_digit(arrayOfTokens[numToken].charAt(3)) &&
         is_num_digit(arrayOfTokens[numToken].charAt(4)) &&
         is_num_digit(arrayOfTokens[numToken].charAt(5))    )
    {
        add_output("Day of month: " + arrayOfTokens[numToken].substr(0,2) + "<BR>",divid);
        add_output("Time: " + arrayOfTokens[numToken].substr(2,2) +":" +
                              arrayOfTokens[numToken].substr(4,2) + " UTC",divid);

        if(arrayOfTokens[numToken].length == 6)
            add_output(" (Time specification is non-compliant!)",divid);

        add_output("<BR>",divid);
        numToken++;
    }
    else
    {
        add_output("Time token not found or with wrong format!",divid);
        return;
    }
    

    // Check if "AUTO" or "COR" token comes next.
    if (arrayOfTokens[numToken] == "AUTO")
    {
        add_output("Report is fully automated, with no human intervention or oversight<BR>",divid);
        numToken++;
    }
    else if (arrayOfTokens[numToken] == "COR")
    {
        add_output("Report is a correction over a METAR or SPECI report<BR>",divid);
        numToken++;
    }

    // Parse remaining tokens
    for (var i=numToken; i<arrayOfTokens.length; i++)
    {
        if(arrayOfTokens[i].length > 0)
        {
            decode_token(arrayOfTokens[i].toUpperCase(),divid);
        }
        else
        {
            add_output("Next token has 0 length<BR>",divid);
        }
    }
       
}

function ejem(text)
{
    alert(text);
}

