<!--

//  Usage:  Functions to calculate and format timing data for FFXI
//  Written by:  Pyogenes from www.pyogenes.com

// basis date is used to convert real time to game time.
// Use UTC functions to allow calculations to work for any timezone
basisDate = new Date();
basisDate.setUTCFullYear(2002, 5, 23); // Set date to 2003-06-23
basisDate.setUTCHours(15, 0, 0, 0);    // Set time to 15:00:00.0000

// moon date is used to determien the current hase of the moon.
// Use UTC functions to allow calculations to work for any timezone
Mndate = new Date();
Mndate.setUTCFullYear(2004, 0, 25); // Set date to 2004-01-25
Mndate.setUTCHours(2, 31, 12, 0);    // Set time to 02:31:12.0000

// basis date for RSE calculations
RSEdate = new Date();
RSEdate.setUTCFullYear(2004, 0, 28); // Set date to 2004-01-28
RSEdate.setUTCHours(9, 14, 24, 0);    // Set time to 09:14:24.0000

// basis date for day of week calculations
Daydate = new Date();
Daydate.setUTCFullYear(2004, 0, 28); // Set date to 2004-01-28
Daydate.setUTCHours(9, 14, 24, 0);    // Set time to 09:14:24.0000

EarthDay = new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
VanaDay = new Array("Firesday", "Earthsday", "Watersday", "Windsday", "Iceday", "Lightningday", "Lightsday", "Darksday");
DayColor = new Array("#DD0000", "#AAAA00", "#0000DD", "#00AA22", "#7799FF", "#AA00AA", "#AAAAAA", "#333333");
weakMagic = new Array("Ice","Lightning","Fire","Earth","Wind","Water","Darkness","Light");
weakColor = new Array("#7799FF", "#AA00AA", "#DD000", "#AAAA00", "#00AA22", "#0000DD", "#333333", "#AAAAAA");

sMonth = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
RSErace = new Array("M. Hume","F. Hume","M. Elvaan","F. Elvaan","M. TaruTaru","F. TaruTaru","Mithra","Galka");
RSEloc = new Array("Gusgen Mines","Shakrami Maze","Ordelle Caves");
BoatSched = new Array("08:00", "16:00", "00:00");

msGameDay   = (24 * 60 * 60 * 1000 / 25); // milliseconds in a game day
msRealDay   = (24 * 60 * 60 * 1000); // milliseconds in a real day

timerId = 0;

// Dictionary Objects

CRYSTAL_DIRECTION = new Object();
CRYSTAL_DIRECTION["fire+strong"] = "West";
CRYSTAL_DIRECTION["fire+same"] = "North-West";
CRYSTAL_DIRECTION["earth+strong"] = "South-East";
CRYSTAL_DIRECTION["earth+same"] = "South";
CRYSTAL_DIRECTION["water+strong"] = "South-West";
CRYSTAL_DIRECTION["water+same"] = "West";
CRYSTAL_DIRECTION["wind+strong"] = "East";
CRYSTAL_DIRECTION["wind+same"] = "South-East";
CRYSTAL_DIRECTION["ice+strong"] = "North-West";
CRYSTAL_DIRECTION["ice+same"] = "East";
CRYSTAL_DIRECTION["lightning+strong"] = "South";
CRYSTAL_DIRECTION["lightning+same"] = "South-West";
CRYSTAL_DIRECTION["light+strong"] = "North";
CRYSTAL_DIRECTION["light+same"] = "North-East";
CRYSTAL_DIRECTION["dark+strong"] = "North-East";
CRYSTAL_DIRECTION["dark+same"] = "North";

DAY_CRYSTAL_FACTOR = new Object();
DAY_CRYSTAL_FACTOR["fire+fire"] = 1;
DAY_CRYSTAL_FACTOR["fire+ice"] = -1;
DAY_CRYSTAL_FACTOR["earth+earth"] = 1;
DAY_CRYSTAL_FACTOR["earth+lightning"] = -1;
DAY_CRYSTAL_FACTOR["water+water"] = 1;
DAY_CRYSTAL_FACTOR["water+fire"] = -1;
DAY_CRYSTAL_FACTOR["wind+wind"] = 1;
DAY_CRYSTAL_FACTOR["wind+earth"] = -1;
DAY_CRYSTAL_FACTOR["ice+ice"] = 1;
DAY_CRYSTAL_FACTOR["ice+wind"] = -1;
DAY_CRYSTAL_FACTOR["lightning+lightning"] = 1;
DAY_CRYSTAL_FACTOR["lightning+water"] = -1;
DAY_CRYSTAL_FACTOR["light+light"] = 1;
DAY_CRYSTAL_FACTOR["light+dark"] = -1;
DAY_CRYSTAL_FACTOR["light+fire"] = 1;
DAY_CRYSTAL_FACTOR["light+earth"] = 1;
DAY_CRYSTAL_FACTOR["light+water"] = 1;
DAY_CRYSTAL_FACTOR["light+wind"] = 1;
DAY_CRYSTAL_FACTOR["light+ice"] = 1;
DAY_CRYSTAL_FACTOR["light+lightning"] = 1;
DAY_CRYSTAL_FACTOR["dark+dark"] = 1;
DAY_CRYSTAL_FACTOR["dark+light"] = -1;
DAY_CRYSTAL_FACTOR["dark+fire"] = -1;
DAY_CRYSTAL_FACTOR["dark+earth"] = -1;
DAY_CRYSTAL_FACTOR["dark+water"] = -1;
DAY_CRYSTAL_FACTOR["dark+wind"] = -1;
DAY_CRYSTAL_FACTOR["dark+ice"] = -1;
DAY_CRYSTAL_FACTOR["dark+lightning"] = -1;

DAY_INDEX_FACTOR = new Object();
DAY_INDEX_FACTOR["0"] = "fire";
DAY_INDEX_FACTOR["1"] = "earth";
DAY_INDEX_FACTOR["2"] = "water";
DAY_INDEX_FACTOR["3"] = "wind";
DAY_INDEX_FACTOR["4"] = "ice";
DAY_INDEX_FACTOR["5"] = "lightning";
DAY_INDEX_FACTOR["6"] = "light";
DAY_INDEX_FACTOR["7"] = "dark";

//**************
// Functions  **
//**************

function vanadielToEarthTime(vanaDate) {
    t = ((vanaDate - ((898 * 360 + 30) * msRealDay)) / 25) + basisDate.getTime();
    return t;
}

function readVanadielDate() {

    vanaDateYear = document.Timer.vanaDateYear.value;
    vanaDateMonth = document.Timer.vanaDateMonth.value;
    vanaDateDay = document.Timer.vanaDateDay.value;

    if (vanaDateYear == "" || vanaDateMonth == "" || vanaDateDay == "") {
        return new Date();
    }

    vanaDate = (vanaDateYear * 360 * msRealDay) + ((vanaDateMonth - 1) * 30 * msRealDay) + ((vanaDateDay - 1) * msRealDay);

    return new Date(vanadielToEarthTime(vanaDate));

}

function getVanadielTime(now)  {

   var vanadielDate = new Object();
   var vanaDate =  ((898 * 360 + 30) * msRealDay) + (now.getTime() - basisDate.getTime()) * 25;

   var vYear = Math.floor(vanaDate / (360 * msRealDay));
   var vMon  = Math.floor((vanaDate % (360 * msRealDay)) / (30 * msRealDay)) + 1;
   var vDate = Math.floor((vanaDate % (30 * msRealDay)) / (msRealDay)) + 1;
   var vHour = Math.floor((vanaDate % (msRealDay)) / (60 * 60 * 1000));
   var vMin  = Math.floor((vanaDate % (60 * 60 * 1000)) / (60 * 1000));
   var vSec  = Math.floor((vanaDate % (60 * 1000)) / 1000);
   var vDay  = Math.floor((vanaDate % (8 * msRealDay)) / (msRealDay));

   if (vYear < 1000) { VanaYear = "0" + vYear; } else { VanaYear = vYear; }
   if (vMon  < 10)   { VanaMon  = "0" + vMon; }  else { VanaMon  = vMon; }
   if (vDate < 10)   { VanaDate = "0" + vDate; } else { VanaDate = vDate; }
   if (vHour < 10)   { VanaHour = "0" + vHour; } else { VanaHour = vHour; }
   if (vMin  < 10)   { VanaMin  = "0" + vMin; }  else { VanaMin  = vMin; }
   if (vSec  < 10)   { VanaSec  = "0" + vSec; }  else { VanaSec  = vSec; }

   vanadielDate.year = VanaYear;
   vanadielDate.month = VanaMon;
   vanadielDate.day = VanaDate;
   vanadielDate.hour = VanaHour;
   vanadielDate.minute = VanaMin;
   vanadielDate.second = VanaSec;
   vanadielDate.dayIndex = vDay;

   return vanadielDate;
}

function clearDetails()  {

      document.getElementById("Details").innerHTML = "";

}

function clearDetails2()  {

      document.getElementById("Details2").innerHTML = "";

}

/* function getEarthTime(now)  {

   var earthTime = formatDate(now.getTime(), 1);
   document.getElementById("eTime").innerHTML = earthTime;
}
*/

function getMoonPhase(timenow)  {

    var localTime = timenow.getTime();
    var moonDays = (Math.floor((localTime - Mndate.getTime()) / msGameDay))  % 84;

    if (moonDays < 0) {
        moonDays = 84 + moonDays;
    }


   // determine phase percentage
    var moonpercent = - Math.round((42 - moonDays) / 42 * 100);
    var mnpercent = "";
         if (moonpercent == -100)  {
              mnpercent = "100% Full Moon";
         }  else if (moonpercent == 0)  {
              mnpercent = "0% New Moon";
         } else if (moonpercent < 0)  {
              mnpercent = -(moonpercent) + "% Waning";
         } else if (moonpercent > 0)  {
              mnpercent = moonpercent + "% Waxing";
         }
         if (moonpercent <= 10 && moonpercent >= -10)  {
              mnpercent = "<FONT COLOR=\"#FF0000\">" + mnpercent + "</FONT>";
         } else if (moonpercent >= 90 || moonpercent <= -90)  {
              mnpercent = "<FONT COLOR=\"#0000FF\">" + mnpercent + "</FONT>";
         }

    var moonPhase = new Object();
    moonPhase.mnpercent = mnpercent;
    moonPhase.moonpercent = moonpercent;

    return moonPhase;


   // new moon starts on day 38 (-10%) ends on 47 (12%)
   // full moon starts at 80 (90%) ends on 5 (-88%)
   // Moon cycle lasts 84 game days.

}

function setDaySched(now)  {

    var timeDiff = now.getTime() - Mndate.getTime();
    var weekStart = 0;
    var dayStart = 0;

    if (timeDiff < 0) {
        weekStart = now.getTime() - (8*msGameDay + (timeDiff % (8 * msGameDay)));
        dayStart = now.getTime() - (msGameDay + (timeDiff % msGameDay));
    }
    else {
        weekStart = now.getTime() - (timeDiff % (8 * msGameDay));
        dayStart = now.getTime() - (timeDiff % msGameDay);
    }

    var repeatCal = document.Timer.DayCount.value;
    var dayOffset = 8;
    var moonpercent = 0;
    var mnpercent = "";
    var startTime = 0;
    var endTime = 0;

    var out = "<table><tr><th></th><th>Day</th>";
    out += "<th>Begins</th><th>Ends</th>";
    out += "<th>Moon Phase</th><th colspan=\"3\">Craft Difficulty</th></tr>";

    if (dayOffset > 7) {
        dayOffset = (dayStart - weekStart) / msGameDay - 2;
        if (dayOffset < 0) {
            dayOffset += 8;
        }

        for ( i = 0; i < repeatCal; i++) {
            startTime = dayStart + (msGameDay * i);
            endTime = startTime + msGameDay;

            moonDays = (Math.floor((startTime - Mndate.getTime()) / msGameDay))  % 84;

            if (moonDays < 0){
                moonDays = 84 + moonDays;
            }

            /*
            if (moonDays < 0) {
                moonDays = 84 + moonDays;
            }
            */

            // determine phase percentage
            moonpercent = - Math.round((42 - moonDays) / 42 * 100);
            if (moonpercent == -100)  {
                mnpercent = "100% Full Moon";
            }  else if (moonpercent == 0)  {
                mnpercent = "0% New Moon";
            } else if (moonpercent < 0)  {
                mnpercent = -(moonpercent) + "% Waning";
            } else if (moonpercent > 0)  {
                mnpercent = moonpercent + "% Waxing";
            }

            if (moonpercent <= 10 && moonpercent >= -10)  {
                mnpercent = "<font COLOR=\"#FF0000\">" + mnpercent + "</font>";
            }
            else if (moonpercent >= 90 || moonpercent <= -90)  {
                mnpercent = "<font COLOR=\"#0000FF\">" + mnpercent + "</font>";
            }

            var dayIndex = (dayOffset + i) % 8;
            var craftDifficulty = calculateDifficulty(dayIndex,moonpercent);

            out += "<tr class=\"calendarLine\" onclick=\"setTimer("+startTime+"); craftDetails("+dayIndex+","+moonpercent+"); craftDetailsDetails();\"><td>";
            out += (i) + "</td><td><font color=\"" + DayColor[(dayOffset + i) % 8] + "\">" + VanaDay[(dayOffset + i) % 8];
            out += "</font></td><td>" + formatDate(startTime, 2) + "</td><td>" + formatDate(endTime, 2) + "</td><td>" + mnpercent;
            out += "</td><td align=\"right\">" + craftDifficulty.min + "</td><td> &nbsp; - &nbsp;</td><td>" + craftDifficulty.max;
            out += "</td></tr>";
        }
    }

    if (repeatCal < 1) { out = ""; } else { out = out + "</table>"; }
    document.getElementById("calendar").innerHTML = out;
}


function formatCountdown(varTime) {

   var dayLeft = varTime / msRealDay;
   var hourLeft = (dayLeft - Math.floor(dayLeft)) * 24;
   var minLeft = (hourLeft - Math.floor(hourLeft)) * 60;
   var secLeft = Math.floor((minLeft - Math.floor(minLeft)) * 60);
   var formattedTime = "";

   dayLeft = Math.floor(dayLeft);
   hourLeft = Math.floor(hourLeft);
   minLeft = Math.floor(minLeft);

   if (minLeft < 10) {minLeft = "0" + minLeft;}
   if (secLeft < 10) {secLeft = "0" + secLeft;}

   if (dayLeft > 0) {
      formattedTime = dayLeft + ":";
      if (hourLeft < 10) {
         formattedTime = formattedTime + "0" + hourLeft + ":";
      } else {
         formattedTime = formattedTime + hourLeft + ":";
      }
   } else if (hourLeft > 0) {
      formattedTime = hourLeft + ":";
   }

   formattedTime = formattedTime + minLeft + ":" + secLeft;
   return formattedTime;
}

function formatDate(varTime, showDay) {

   var varDate = new Date(varTime);
   var yyyy = varDate.getFullYear();
   var mm = varDate.getMonth() + 1;
   if (mm < 10) { mm = "0" + mm; }

   var dd = varDate.getDate();
   if (dd < 10) { dd = "0" + dd; }

   var day = varDate.getDay();

   var hh = varDate.getHours();
   if (hh < 10) { hh = "0" + hh; }

   var min = varDate.getMinutes();
   if (min < 10) { min = "0" + min; }

   var ss = varDate.getSeconds();
   if (ss < 10) { ss = "0" + ss; }

   if (showDay == 1)  {
      dateString = EarthDay[day] + ", " + sMonth[mm-1] + " " + dd + ", " + yyyy + " " + hh + ":" + min + ":" + ss;
   } else if (showDay == 2)  {
      dateString = sMonth[mm-1] + " " + dd + ",  " + hh + ":" + min + ":" + ss;
   }
   return dateString;
}


function calculateDifficulty (dayIndex, moonpercent)
{
    var skillCap = document.craftInput.skillCap.value;
    var skillCurrent = document.craftInput.skillLevel.value;

    if (skillCap=="" || skillCurrent=="")
    {
        return "";
    }

    var day = DAY_INDEX_FACTOR[dayIndex];

    var crystal = document.craftInput.crystal.value;

    var dayCrystalFactor = DAY_CRYSTAL_FACTOR[day + "+" + crystal];

    if (dayCrystalFactor == null) {
        dayCrystalFactor = 0;
    }

    var sumOfFactors = (Math.abs(moonpercent)-50)/50 + dayCrystalFactor;
    var noSupport_strongDirection = -0.5;
    var advancedSupport_sameDirection = 2.5;

    var baseDifficulty = skillCap - skillCurrent;
    var moonDayDifficulty = baseDifficulty - sumOfFactors;

    var difficulty = new Object();
    difficulty.min = truncate(moonDayDifficulty - advancedSupport_sameDirection);
    difficulty.moonDay = moonDayDifficulty;
    difficulty.base = baseDifficulty;
    difficulty.max = truncate(moonDayDifficulty - noSupport_strongDirection);

    //return minDifficulty.toFixed(2) + " - " + maxDifficulty.toFixed(2);
    return difficulty;

}

function craftDetails(dayIndex,moonpercent)  {

    var difficulty = calculateDifficulty(dayIndex,moonpercent);

    var support = new Array(2,1,0);
    var direction = new Array(0.5,0,-0.5);
    var supportNames = new Array("Adv. Support","Free Support","No Support");

    var crystal = document.craftInput.crystal.value;

    var html = "<table><tr><th width=\"25%\"></th><th align=\"center\">Facing " + CRYSTAL_DIRECTION[crystal + "+same"] + "</th>";
    html += "<th align=\"center\">Direction Neutral</th>";
    html += "<th align=\"center\">Facing " + CRYSTAL_DIRECTION[crystal + "+strong"] + "</th></tr>";

    for (var i=0; i < support.length; i++) {
            html = html + "<tr><td>" + supportNames[i] + "</td>";
        for (var j=0; j < direction.length; j++) {
            difficultyValue = truncate(difficulty.moonDay - direction[j] - support[i]);
            html += "<td align=\"center\" onmouseover=\"craftDetailsDetails(" + difficultyValue + ");\">" + difficultyValue  + "</td>";
        }
        html += "</tr>";

    }

    html += "</table>"

   document.getElementById("Details").innerHTML = html;
}

function craftDetailsDetails(difficultyValue) {

    var html = "<p>";

    if (difficultyValue <= 0) {
        html+= "<b> &lt;0 The Redundant zone </b> &nbsp (" + difficultyValue + ")<br/>";
        html+= "Skill ups can be hard to obtain, because the recipe is too easy to improve your skill. There are just too many factors helping you succeed, so there is no chance to learn.";
    }
    else if (difficultyValue >0 && difficultyValue <= 2) {
        html+= "<b>0-2 The Success zone</b> &nbsp (" + difficultyValue + ")<br/>";
        html+= "There is a very good chance of success. Skill ups will occur, but some will be lost due to the recipe being relatively easy compared to your current skills. Best used when the recipe is break even or profit, and/or when the ingredients are expensive.";
    }
    else if (difficultyValue >2 && difficultyValue <= 4) {
        html+= "<b>2-4 The Prime Skill up zone</b> &nbsp (" + difficultyValue + ")<br/>";
        html+= "There is a very good chance for skill ups. Failures will occur, but at a fair trade off for skill ups (in most cases). It is fairly easy to get the craft modifier to be in this range from anywhere from 7/8-1 levels from cap.";
    }
    else if (difficultyValue >4 && difficultyValue <= 6) {
        html+= "<b>4-6 Skill from fails zone</b> &nbsp (" + difficultyValue + ")<br/>";
        html+= "The chance of a skill up is okay, but it is best to be within 5 levels of the cap so that skill ups can still be obtained from failures. The ingredients had better be cheap, or you will be digging yourself into a hole.";
    }
    else if (difficultyValue > 6) {
        html+= "<b>&gt;6 High risk, low reward zone</b> (" + difficultyValue + ")<br/>";
        html+= "<br>There is no good reason to be in this zone. This is only for the pure power leveler who could care less about expenses. Please move onto another craft/recipe before wasting your gil here.";
    }
    else {
        html+= "Hover over the values in the crafting modifier table to see a description.";
    };

    html += "</p>";

    document.getElementById("Details2").innerHTML = html;
}

function setVanadielTime(now) {

    var vanaDate = getVanadielTime(now);

    var VanaTime = "<font color=" + DayColor[vanaDate.dayIndex] + ">" + VanaDay[vanaDate.dayIndex] + "</font>:  ";
    VanaTime += vanaDate.year + "-" + vanaDate.month + "-" + vanaDate.day + "  " + vanaDate.hour + ":" + vanaDate.minute + ":" + vanaDate.second;

    document.getElementById("vTime").innerHTML = VanaTime;

}

function setEarthTime(now) {

   var earthTime = formatDate(now.getTime(), 1);
   document.getElementById("eTime").innerHTML = earthTime;

}

function setMoonPhase(now) {

    var moonPhase = getMoonPhase(now);
    document.getElementById("mPhase").innerHTML = moonPhase.mnpercent;

}

function setVanadielDateValue(now) {

    var vanadielDate = getVanadielTime(now);

    document.Timer.vanaDateYear.value = vanadielDate.year;
    document.Timer.vanaDateMonth.value = vanadielDate.month;
    document.Timer.vanaDateDay.value = vanadielDate.day;

}

function setTimer(time) {

    var now = new Date(time);

    setVanadielTime(now);
    setEarthTime(now);
    setMoonPhase(now);

    clearTimeout(timerId);
}

function setBaseDifficulty() {

    //var difficulty = craftDifficulty();

    var skillCap = document.craftInput.skillCap.value;
    var skillLevel = document.craftInput.skillLevel.value;
    var difficulty = skillCap - skillLevel;

    //difficulty.base = "yournamehere";

    //document.getElementById("baseDifficulty").innerHTML = difficulty.base;
    //document.getElementById("baseDifficulty").innerHTML = difficulty;
    document.getElementById("baseDifficulty").innerHTML = difficulty;
}

function getDayProperties(now) {

    // determine phase percentage
    var moonPhase = getMoonPhase(now);
    var vanaDate = getVanadielTime(now);
    craftDetails(vanaDate.dayIndex,moonPhase.moonpercent);
}

function readEarthDate() {

    var eDate = new Date();
    var eYear = document.Timer.earthDateYear.value;
    var eMonth = document.Timer.earthDateMonth.value;
    var eDay = document.Timer.earthDateDay.value;

    eDate.setFullYear(eYear);
    eDate.setMonth(eMonth-1);
    eDate.setDate(eDay);
    eDate.setHours(0);
    eDate.setMinutes(0);
    eDate.setSeconds(0);
    eDate.setMilliseconds(0);

    return eDate;

}

function setEarthDateValue(now) {

    document.Timer.earthDateYear.value = now.getFullYear();
    document.Timer.earthDateMonth.value = now.getMonth()+1;
    document.Timer.earthDateDay.value = now.getDate();

}

function updateEverything(now) {

   setTimer(now);
   setDaySched(now);
   setBaseDifficulty();
   getDayProperties(now);
}

function printPageEarth() {

   if (timerId != 0) {
      clearTimeout(timerId);
   }

    var now = new Date();
    now = readEarthDate();
    updateEverything(now);

}

function printPage() {

   if (timerId != 0) {
      clearTimeout(timerId);
   }

   var now = readVanadielDate();
   updateEverything(now);
}

function printPageNow() {

   if (timerId != 0) {
      clearTimeout(timerId);
   }

    var now = new Date();
    setVanadielDateValue(now);
    setEarthDateValue(now);
    updateEverything(now);
    timerId = setTimeout("printPageNow()", 10000);
}

function printCraft() {

    var now = readVanadielDate();
    setVanadielDateValue(now);
    setEarthDateValue(now);
    updateEverything(now);
}

function truncate(optionalRateFix) {

    optionalRateFix = Math.round(optionalRateFix*100).toString();
    optionalRateFix = optionalRateFix.substring(0,optionalRateFix.length-2)+"."+
    optionalRateFix.substring(optionalRateFix.length-2,optionalRateFix.length);

    return optionalRateFix;
}