function GetInterest()
{
    var oInterest = GetElement("interest");
    if (oInterest == null)
        return -1;
    if (oInterest.value == "")
    {
        // alert("Please enter the interest rate.");
        alert("Моля, въведете лихвен процент.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oInterest.value))
    {
        // alert("An error occurred while retrieving the interest rate.\nPlease enter non-negative value (use dot as a decimal separator).");
        alert("Има грешка при обработването на лихвения процент.\nМоля, въвеждайте само положителни стойности\n(използвайте точка за разделителен знак).");
        return -1;
    }
    if ((oInterest.value > 50))
    {
        // alert("The interest rate must be less than or equal to 50%.");
        alert("Лихвеният процент трябва да е по-малък, или равен на 50%.");
        return -1;
    }
    var fInterest = new Number(oInterest.value);
    return (fInterest / 100);
}

function GetTarget()
{
    var oTarget = GetElement("target");
    if (oTarget == null)
        return -1;
    if (oTarget.value == "")
    {
        // alert("Please enter your financial goal.");
        alert("Моля, въведете финансовата си цел.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oTarget.value))
    {
        // alert("An error occurred while retrieving the financial goal.\nPlease enter non-negative value (use dot as a decimal separator).");
        alert("Има грешка при обработването на финансовата цел.\nМоля, въвеждайте само положителни стойности\n(използвайте точка за разделителен знак).");
        return -1;
    }
    var fTarget = new Number(oTarget.value);
    return fTarget;
}

function GetActual()
{
    var oActual = GetElement("actual");
    if (oActual == null)
        return -1;
    if (oActual.value == "")
    {
        // alert("Please enter the actual value of your savings.");
        alert("Моля въведете актуалната стойност на вашите спестявания.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oActual.value))
    {
        // alert("An error occurred while retrieving the actual value.\nPlease enter non-negative value (use dot as a decimal separator).");
        alert("Има грешка при обработването на актуалната\nстойност на вашите спестявания. Моля, въвеждайте само\nположителни стойности (използвайте точка за разделителен знак).");
        return -1;
    }
    var fActual = new Number(oActual.value);
    return fActual;
}

function GetLength()
{
    var oLengthYears = GetElement("lengthyears");
    var oLengthMonths = GetElement("lengthmonths");
    if ((oLengthYears == null) || (oLengthMonths == null))
        return -1;
    if ((oLengthYears.value == "") && (oLengthMonths.value == ""))
    {
        // alert("Please enter the requested length of your savings.");
        alert("Моля, въведете желания срок за спестяване.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]{1,3}$", "g");
    if ((oLengthYears.value != "") && (!oRegExp.test(oLengthYears.value)))
    {
        // alert("An error occurred while retrieving the length of savings in years.\nPlease enter the whole non-negative number less than 1000.");
        alert("Има грешка при обработването на желания срок за спестяване.\nМоля, въвеждайте цели положителни стойности, но по-малки от 1000.");
        return -1;
    }
    oRegExp = new RegExp("^[0-9]{1,3}$", "g");
    if ((oLengthMonths.value != "") && (!oRegExp.test(oLengthMonths.value)))
    {
        // alert("An error occurred while retrieving the length of savings in months.\nPlease enter the whole non-negative number less than 1000.");
        alert("Има грешка при обработването на желания срок за спестяване в месеци.\nМоля, въвеждайте цели положителни стойности, но по-малки от 1000.");
        return -1;
    }

    var nLengthYears, nLengthMonts;
    if (oLengthYears.value != "")
        nLengthYears = new Number(oLengthYears.value);
    else
        nLengthYears = 0
    if (oLengthMonths.value != "")
        nLengthMonths = new Number(oLengthMonths.value);
    else
        nLengthMonths = 0;
    if (nLengthYears + nLengthMonths == 0)
    {
        // alert("The savings length must not be zero.");
        alert("Срокът на спестяване не трябва да е нула.");
        return -1;
    }
    return nLengthYears * 12 + nLengthMonths;
}

function GetMonthly()
{
    var oMonthly = GetElement("monthly");
    if (oMonthly == null)
        return -1;
    if (oMonthly.value == "")
    {
        // alert("Please enter the value of monthly savings.");
        alert("Моля, въведете данни за месечните спестявания.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oMonthly.value))
    {
        // alert("An error occurred while retrieving the monthly savings value.\nPlease enter non-negative value (use dot as a decimal separator).");
        alert("Има грешка при обработването на месечните спестявания.\nМоля, въвеждайте само положителни стойности\n(използвайте точка за разделителен знак).");
        return -1;
    }
    var fMonthly = new Number(oMonthly.value);
    return fMonthly;
}

function ComputeTarget(fInterest, fActual, nLength, fMonthly)
{
    var i, fTarget;
    var fBeta = Math.pow(1 + fInterest, 1/12);
    fTarget = (fActual + fMonthly) * Math.pow(fBeta, nLength);
    for (i = 2; i <= nLength; i++)
    {
        fTarget += fMonthly * Math.pow(fBeta, nLength + 1 - i);
    }
    return fTarget;
}

function DreamTarget()
{
    var fInterest = GetInterest();
    if (fInterest == -1) return;
    var fActual = GetActual();
    if (fActual == -1) return;
    var nLength = GetLength();
    if (nLength == -1) return;
    var fMonthly = GetMonthly();
    if (fMonthly == -1) return;
    var fTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
    var oResult = GetElement("target");
    if (oResult == null) return;
    oResult.value = Math.floor(fTarget);    
}

function DreamInterest()
{
    var fTarget = GetTarget();
    if (fTarget == -1) return;
    var fActual = GetActual();
    if (fActual == -1) return;
    var nLength = GetLength();
    if (nLength == -1) return;
    var fMonthly = GetMonthly();
    if (fMonthly == -1) return;
    
    var oResult = GetElement("interest");
    if (oResult == null) return;
    oResult.value = "";
    
    if (fTarget < fActual + nLength * fMonthly)
    {
        // alert("The financial goal is too low.\nThat goal can be achieved even without interest in shorter time.");
        alert("Финансовата цел е твърде ниска.\nТази цел може да бъде постигната дори и без лихви за кратък период.");
        return;
    }        
    
    var fInterest = 0.2;
    var fEstTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
    if (fTarget > fEstTarget)
    {
        // alert("The interest rate would be too high and unrealistic.\nPlease enter lower financial goal, increase monthly savings\nor extend the savings period.");
        alert("Лихвеният процент е прекалено голям и нереалистичен.\nМоля, намалете финансовата цел, увеличете месечните\nвноски, или увеличете периода за инвестиране.");
        return;
    }
    
    fInterest = 0.1;
    var fMin = 0; fMax = 0.2;
    while (fMax - fMin > 0.00001)
    {
        fEstTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
        if (fTarget < fEstTarget)
        {
            fMax = fInterest;
        }
        else
        {
            fMin = fInterest;
        }
        fInterest = (fMin + fMax) / 2;
    }
    
    oResult.value = Math.ceil(fInterest * 10000) / 100;
}

function DreamActual()
{
    var fInterest = GetInterest();
    if (fInterest == -1) return;
    var fTarget = GetTarget();
    if (fTarget == -1) return;
    var nLength = GetLength();
    if (nLength == -1) return;
    var fMonthly = GetMonthly();
    if (fMonthly == -1) return;
    
    var oResult = GetElement("actual");
    if (oResult == null) return;
    oResult.value = "";
    
    if (fTarget < ComputeTarget(fInterest, 0, nLength, fMonthly))
    {
        // alert("The financial goal is too low.\nIt can be achieved even without any\nstarting value in shorter period of time.");
        alert("Финансовата цел е твърде ниска.\nТази цел може да бъде постигната дори\nи без начален капитал за кратък период.");
        return;
    }        
    
    var fActual = fTarget / 2;
    var fMin = 0; fMax = fTarget;
    while (fMax - fMin > 0.1)
    {
        fEstTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
        if (fTarget < fEstTarget)
        {
            fMax = fActual;
        }
        else
        {
            fMin = fActual;
        }
        fActual = (fMin + fMax) / 2;
    }
    
    oResult.value = Math.ceil(fActual);
}

function DreamLength()
{
    var fInterest = GetInterest();
    if (fInterest == -1) return;
    var fTarget = GetTarget();
    if (fTarget == -1) return;
    var fActual = GetActual();
    if (fActual == -1) return;
    var fMonthly = GetMonthly();
    if (fMonthly == -1) return;
    
    var oResultYears = GetElement("lengthyears");
    var oResultMonths = GetElement("lengthmonths");
    if ((oResultYears == null) || (oResultMonths == null)) return;
    oResultYears.value = "";
    oResultMonths.value = "";
    
    if (fTarget < fActual + fMonthly)
    {
        // alert("The financial goal is too low;\nthe sum of money is ready at instant.");
        alert("Финансовата цел е твърде ниска. Тази цел вече е постигната.");
        return;
    }        
    
    if (fTarget > ComputeTarget(fInterest, fActual, 1200, fMonthly))
    {
        // alert("The financial goal is too high.\nTo achieve such a goal would require more\nthan a century in the conditions specified.");
        alert("Финансовата цел е твърде висока.\nЗа да се постигне при зададените условия ще има нужда от повече от век.");
        return;
    }
    
    var nLength = 600;
    var nMin = 0; nMax = 1200;
    while (nMax - nMin > 1)
    {
        fEstTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
        if (fTarget < fEstTarget)
        {
            nMax = nLength;
        }
        else
        {
            nMin = nLength;
        }
        nLength = Math.floor((nMin + nMax) / 2);
    }
    
    fEstTarget = ComputeTarget(fInterest, fActual, nMin, fMonthly);
    if (fTarget <= fEstTarget)
    {
        oResultYears.value = Math.floor(nMin / 12);
        oResultMonths.value = nMin % 12;
    }
    else
    {
        oResultYears.value = Math.floor(nMax / 12);
        oResultMonths.value = nMax % 12;
    }
}

function DreamMonthly()
{
    var fInterest = GetInterest();
    if (fInterest == -1) return;
    var fTarget = GetTarget();
    if (fTarget == -1) return;
    var fActual = GetActual();
    if (fActual == -1) return;
    var nLength = GetLength();
    if (nLength == -1) return;
    
    var oResult = GetElement("monthly");
    if (oResult == null) return;
    oResult.value = "";
    
    if (fTarget < ComputeTarget(fInterest, fActual, nLength, 0))
    {
        // alert("The financial goal is too low.\nThe goal will be achieved only by the interest rate\nin the time specified, no savings are necessary.");
        alert("Финансовата цел е твърде ниска.\nТя ще бъде постигната само от лихви за посочения период,\nняма нужда от допълнителни спестявания.");
        return;
    }        
    
    var fMin = 0; fMax = (fTarget - fActual * Math.pow(1 + fInterest, nLength / 12)) / nLength;
    var fMonthly = fMax / 2;
    while (fMax - fMin > 0.1)
    {
        fEstTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
        if (fTarget < fEstTarget)
        {
            fMax = fMonthly;
        }
        else
        {
            fMin = fMonthly;
        }
        fMonthly = (fMin + fMax) / 2;
    }
    
    oResult.value = Math.ceil(fMonthly);
}
