function GetInterest()
{
    var oInterest = GetElement("interest");
    if (oInterest == null)
        return -1;
    if (oInterest.value == "")
    {
        alert("Zadejte prosím předpokládaný roční výnos.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oInterest.value))
    {
        alert("Chyba při zpracování hodnoty výnosu.\nZadejte prosím nezáporné desetinné číslo (s desetinnou tečkou).");
        return -1;
    }
    if ((oInterest.value > 50))
    {
        alert("Hodnota ročního výnosu musí být menší nebo rovna 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("Zadejte prosím Váš finanční cíl.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oTarget.value))
    {
        alert("Chyba při zpracování hodnoty finančního cíle.\nZadejte prosím nezáporné desetinné číslo (s desetinnou tečkou).");
        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("Zadejte prosím Váš stávající stav úspor.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oActual.value))
    {
        alert("Chyba při zpracování hodnoty stavu úspor.\nZadejte prosím nezáporné desetinné číslo (s desetinnou tečkou).");
        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("Zadejte prosím požadovanou délku spoření.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]{1,3}$", "g");
    if ((oLengthYears.value != "") && (!oRegExp.test(oLengthYears.value)))
    {
        alert("Chyba při zpracování roků délky spoření.\nZadejte prosím kladné celé číslo menší než 1000.");
        return -1;
    }
    oRegExp = new RegExp("^[0-9]{1,3}$", "g");
    if ((oLengthMonths.value != "") && (!oRegExp.test(oLengthMonths.value)))
    {
        alert("Chyba při zpracování měsíců délky spoření.\nZadejte prosím kladné celé číslo menší než 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("Délka spoření nesmí být nula.");
        return -1;
    }
    return nLengthYears * 12 + nLengthMonths;
}

function GetMonthly()
{
    var oMonthly = GetElement("monthly");
    if (oMonthly == null)
        return -1;
    if (oMonthly.value == "")
    {
        alert("Zadejte prosím hodnotu měsíční úložky.");
        return -1;
    }
    var oRegExp = new RegExp("^[0-9]+(\.[0-9]+)?$", "g");
    if (!oRegExp.test(oMonthly.value))
    {
        alert("Chyba při zpracování hodnoty měsíční úložky.\nZadejte prosím nezáporné desetinné číslo (s desetinnou tečkou).");
        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("Finanční cíl je příliš nízký.\nDanou částku je možno i bez výnosů naspořit v kratším čase.");
        return;
    }        
    
    var fInterest = 0.2;
    var fEstTarget = ComputeTarget(fInterest, fActual, nLength, fMonthly);
    if (fTarget > fEstTarget)
    {
        alert("Roční výnos by musel být nereálně vysoký.\nZadejte nižší finanční cíl, zvyšte měsíční úložky\nnebo prodlužte dobu spoření.");
        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("Finanční cíl je nízký.\nDanou částku je možno i bez počáteční naspořené\nčástky naspořit v kratším čase.");
        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("Finanční cíl je nízký,\npožadované finance jsou okamžitě k dispozici.");
        return;
    }        
    
    if (fTarget > ComputeTarget(fInterest, fActual, 1200, fMonthly))
    {
        alert("Finanční cíl je příliš vysoký.\nK naspoření požadované částky za daných podmínek\nby bylo potřeba více než jedno století.");
        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("Finanční cíl je nízký.\nPeníze se do požadované hodnoty zhodnotí za daných\npodmínek samy i bez dalšího spoření.");
        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);
}
