//
// Original: http://www.diaware.de/html/roemzahl.html
//
// Changes: Tomasz Lewandowski
// admin@webbe.de
// 04.06.2004 11:54

// Wertigkeit ermitteln
function romanValancy(digit)
{
  switch(digit.toUpperCase())
  {
    case "M": return 1000;
    case "D": return 500;
    case "C": return 100;
    case "L": return 50
    case "X": return 10;
    case "V": return 5;
    case "I": return 1;
    default:  return 0;
  }
  return 0;
}

// Prüfung ob Grundzahl
function isMainchar(digit)
{
  switch (digit.toUpperCase())
  {
    case "M": return 1;
    case "C": return 1;
    case "X": return 1;
    case "I": return 1;
    default:  return 0;
  }
  return 0;
}

// Kommentar ausgeben
function printComment(text)
{
  document.getElementById('comment').value += text+"\n";
}

// Kommentarfeld leeren
function initComment()
{
  document.getElementById('comment').value = '';
}

// Umrechnung Dezimalzahl zu langer römischen Zahl
function decimal2romanLong(decimalNumber)
{
  // Ganze-Zahl ermitteln
  decimalNumber = parseInt(decimalNumber)

  // Die Umrechnung erfolgt ähnlich wie bei der
  // kurzen Version, jedoch mit dem Unterschied,
  // dass für die einzelnen Ziffern in der Dezimalzahl
  // vordefinierte römische Zahlen genommen werden
  var romanNumber = "";
  var power = 1000;
  var digit = 0;

  while( decimalNumber > 0 )
  {
    // Stellenwert ermitteln
    digit = Math.floor(decimalNumber / power);

    // Zahl um die aktuelle Wertigkeit verringern
    // d.h. aus 1234 wird 234 usw.
    decimalNumber %= power;

    // ist kein Wert zur aktuellen Wertigkeit vorhanden
    // dann Wertigkeit verringern
    // d.h. aus 1000 wird 100 usw.
    if( digit == 0 )
    {
      power /= 10;
    }

    // es sind 1000er
    if( power == 1000 )
    {
      if( digit == 1 ) romanNumber += "M";
      if( digit == 2 ) romanNumber += "MM";
      if( digit == 3 ) romanNumber += "MMM";
      if( digit == 4 ) romanNumber += "MMMM";
    }

    // es sind 100er
    if( power == 100 )
    {
      if( digit == 1 ) romanNumber += "C";
      if( digit == 2 ) romanNumber += "CC";
      if( digit == 3 ) romanNumber += "CCC";
      if( digit == 4 ) romanNumber += "CD";
      if( digit == 5 ) romanNumber += "D";
      if( digit == 6 ) romanNumber += "DC";
      if( digit == 7 ) romanNumber += "DCC";
      if( digit == 8 ) romanNumber += "DCCC";
      if( digit == 9 ) romanNumber += "CM";
    }

    // es sind 10er
    if( power == 10 )
    {
      if( digit == 1 ) romanNumber += "X";
      if( digit == 2 ) romanNumber += "XX";
      if( digit == 3 ) romanNumber += "XXX";
      if( digit == 4 ) romanNumber += "XL";
      if( digit == 5 ) romanNumber += "L";
      if( digit == 6 ) romanNumber += "LX";
      if( digit == 7 ) romanNumber += "LXX";
      if( digit == 8 ) romanNumber += "LXXX";
      if( digit == 9 ) romanNumber += "XC";
    }

    // es sind 1er
    if( power == 1 )
    {
      if( digit == 1 ) romanNumber += "I";
      if( digit == 2 ) romanNumber += "II";
      if( digit == 3 ) romanNumber += "III";
      if( digit == 4 ) romanNumber += "IV";
      if( digit == 5 ) romanNumber += "V";
      if( digit == 6 ) romanNumber += "VI";
      if( digit == 7 ) romanNumber += "VII";
      if( digit == 8 ) romanNumber += "VIII";
      if( digit == 9 ) romanNumber += "IX";
    }
  }

  return romanNumber;
}

// Umrechnung Dezimalzahl zu kurzer römischen Zahl
function decimal2romanShort(decimalNumber)
{
  //  Bilden eines Arrays mit den Sonderzahlen im Römischen Zahlensystem
  //         | Grundzahlen                            | Zwischenzahlen
  //  -------|----------------------------------------|---------------------------------------
  //  1er    | 1   = I;                               | 4   = IV; 5   = V;
  //  10er   | 9   = IX; 10  = X;                     | 40  = XL; 49  = IL; 50  = L;
  //  100er  | 90  = XC; 99  = IC; 100 = C;           | 400 = CD; 490 = XD; 499 = ID; 500 = D
  //  1000er | 900 = CM; 990 = XM; 999 = IM; 1000 = M |

  var special = new Array(19);
  for(var i = 0; i<special.length; i++)
  {
    special[i]=new Array(2);
  }
  special[ 0][0] = 1;    special[ 0][1] = "I";
  special[ 1][0] = 4;    special[ 1][1] = "IV";
  special[ 2][0] = 5;    special[ 2][1] = "V";
  special[ 3][0] = 9;    special[ 3][1] = "IX";
  special[ 4][0] = 10;   special[ 4][1] = "X";
  special[ 5][0] = 40;   special[ 5][1] = "XL";
  special[ 6][0] = 49;   special[ 6][1] = "IL";
  special[ 7][0] = 50;   special[ 7][1] = "L";
  special[ 8][0] = 90;   special[ 8][1] = "XC";
  special[ 9][0] = 99;   special[ 9][1] = "IC";
  special[10][0] = 100;  special[10][1] = "C";
  special[11][0] = 400;  special[11][1] = "CD";
  special[12][0] = 490;  special[12][1] = "XD";
  special[13][0] = 499;  special[13][1] = "ID";
  special[14][0] = 500;  special[14][1] = "D";
  special[15][0] = 900;  special[15][1] = "CM";
  special[16][0] = 990;  special[16][1] = "XM";
  special[17][0] = 999;  special[17][1] = "IM";
  special[18][0] = 1000; special[18][1] = "M"

  // Jetzt werden alle Sonderzahlen von der größten Zahl
  // rückwärts von der Dezimalzahl abgezogen
  // und so die römische Zahl ermittelt.
  // Das Ergebnis ist eine Kurzversion der Dezimalzahl
  // die jedoch nicht immer den Regeln entspricht
  var romanNumber = "";
  for( var i=(special.length-1); i>=0; i-- )
  {
    while ( decimalNumber >= special[i][0] )
    {
      romanNumber   += special[i][1];
      decimalNumber -= special[i][0];
    }
  }
  return romanNumber;
}

// Römisch nach dezimal
function roman2decimal()
{
  initComment();

  // haben alle römischen Zahlen eine gültige Wertigkeit
  var romanNumber = document.getElementById('roman').value;
  for(var i=0; i<romanNumber.length; i++ )
  {
    if( romanValancy( romanNumber.charAt(i) ) == 0 )
    {
      printComment("Fehler: Die römische Zahl enthält ein ungültiges Zeichen: '" + romanNumber.charAt(i) +"'");
      return;
    }
  }

  // Dezimalzahl bilden
  var decimalNumber = roman2decimalInternal(romanNumber,1);

  document.getElementById('decimal').value = decimalNumber;
  if( decimalNumber == 0 ) return;

  // kurze Darstellung der römischen Zahl
  var romanNumberShort = decimal2romanShort(decimalNumber);

  if( romanNumberShort != romanNumber )
  {
    printComment("Die römische Zahl lässt sich alternativ darstellen: " + romanNumberShort);
  }
}

function roman2decimalInternal(romanNumber, art)
{
  // maximale Wertigkeit
  var maxValancy  = romanValancy("M") + 1;

  // alte Wertigkeit
  var oldValancy  = romanValancy("M");

  // aktuelle Wertigkeit
  var curValancy  = 0;

  // Zähler von gleichen Ziffern
  var charCounter = 0;

  // Ziffertyp
  // 1 = Grundzahlen
  // 0 = Zwischenzahlen
  // 2 = subtraktive Kombination
  var charType = 0;

  // Dezimalzahl
  var decimalNumber = 0;

  // untersuche alle römischen Ziffern
  for (var i = 0; i < romanNumber.length; i++ )
  {
    // handelt es sich um eine subtraktive Kombination ?
    if (
         // aktuelle Stelle ist nicht die letzte Stelle
         (i + 1) < romanNumber.length &&
         // Wertigkeit links ist kleiner als Wertigkeit rechts
         romanValancy(romanNumber.charAt(i)) < romanValancy( romanNumber.charAt(i + 1))
       )
    {
      // subtraktive Kombination immer mit Grundzahlen vor beliebigen Zeichen!
      if ( isMainchar( romanNumber.charAt(i) ) == 0 )
      {
        printComment( "Verstoß gegen Regel 2: die Kombination '"
                    + romanNumber.charAt(i) + romanNumber.charAt(i+1)
                    + "' ist falsch! Zwischenzahlen (hier '" + romanNumber.charAt(i) + "')"
                    + " dürfen nicht subtrahiert werden." );
        return 0;
      }
      else
      {
        // es ist eine subtraktive Kombination!
        // die Subtraktion ausführen und Wertigkeit ermitteln
        curValancy = romanValancy( romanNumber.charAt(i + 1) ) - romanValancy( romanNumber.charAt(i) );
        charType = 2;
      }
    }
    else
    {
      // Wertigkeit ermitteln
      curValancy = romanValancy( romanNumber.charAt(i) );
      charType = isMainchar( romanNumber.charAt(i) );
    }

    // Prüfen nach absteigender Wertigkeit
    if ( oldValancy < curValancy )
    {
      printComment( "Fehler: die einzelnen Zeichen sind nicht von links"
                  + " nach rechts mit absteigender Wertigkeit angeordnet.");
      return 0;
    }

    // keine strenge Prüfung
    if ( art == 0 )
    {
      // Prüfen ob die aktuell maximal erlaubte Wertigkeit kleiner/gleich ist
      // als die Wertigkeit der aktuellen Ziffer vor der subtraktiven Kombination
      // z.B: XCL ist nicht erlaubt da L eine höhere Wertigkeit hat als X
      if ( charType != 2 && maxValancy <= romanValancy( romanNumber.charAt(i)) )
      {
        printComment( "Warnung: das Zeichen '" + romanNumber.charAt(i)
                    + "' an Stelle " + (i + 1) + " hat die gleiche oder eine höhere Wertigkeit"
                    + " als ein Zeichen in einer subtraktiven Kombination links davon." );
      }

      // Prüfen ob die aktuell maximal erlaubte Wertigkeit in der rechten subtraktiven
      // Kombination kleiner/gleich ist als die Wertigkeit der aktuellen Ziffer vor der
      // linken subtraktiven Kombination
      // z.B: CDCD ist nicht erlaubt da das zweite D eine höhere Wertigkeit hat als erlaubt
      if ( charType == 2 && maxValancy <= romanValancy( romanNumber.charAt(i+1)) )
      {
        printComment( "Warnung2: die subtraktive Kombination '"
                    + romanNumber.charAt(i) + romanNumber.charAt(i + 1)
                    + "' enthält Zeichen mit gleicher oder höherer Wertigkeit als ein Zeichen"
                    + " in einer subtraktiven Kombination links davon." );
      }
    }
    // strenge Prüfung
    else
    {
      // Prüfen ob die aktuell maximal erlaubte Wertigkeit kleiner ist
      // als die Wertigkeit der aktuellen Ziffer vor der subtraktiven Kombination
      // z.B: XCL ist nicht erlaubt da L eine höhere Wertigkeit hat als X
      if ( charType != 2 && maxValancy < romanValancy( romanNumber.charAt(i)) )
      {
        printComment( "Warnung: das Zeichen '" + romanNumber.charAt(i)
                    + "' an Stelle " + (i + 1) + " hat eine höhere Wertigkeit als ein Zeichen"
                    + " in einer subtraktiven Kombination links davon." )
      }

      // Prüfen ob die aktuell maximal erlaubte Wertigkeit in der rechten subtraktiven
      // Kombination kleiner ist als die Wertigkeit der aktuellen Ziffer vor der
      // linken subtraktiven Kombination
      // z.B: CDCD ist nicht erlaubt da das zweite D eine höhere Wertigkeit hat als erlaubt
      if ( charType == 2 && maxValancy < romanValancy( romanNumber.charAt(i + 1)) )
      {
        printComment( "Warnung: die subtraktive Kombination '" + (i+1) + " "
                    + romanNumber.charAt(i) + romanNumber.charAt(i + 1)
                    + "' enthält ein Zeichen '" + romanNumber.charAt(i + 1)
                    + "' mit einer höheren Wertigkeit als ein Zeichen"
                    + " in einer subtraktiven Kombination links davon." );
      }

      // Prüfen ab Regel 3 erfüllt ist, d.h. die Wertigkeiten bei der
      // subtraktiven Kombination können sich nur um 1 unterscheiden
      // d.h. erlaubt sind: IV oder IX und nicht erlaubt sind IC oder XD
      if ( charType == 2 &&
          (romanValancy(romanNumber.charAt(i + 1)) / romanValancy(romanNumber.charAt(i)) ) > 10 )
      {
        printComment( "Verstoß gegen Regel 3: Bei '"
                    + romanNumber.charAt(i) + romanNumber.charAt(i + 1)
                    + "' darf kein " + romanNumber.charAt(i) + " vor einem "
                    + romanNumber.charAt(i + 1) + " stehen!" );
      }
    }

    // Prüfen nach gleichen Ziffern
    if ( i > 0 && charType != 2 && oldValancy == curValancy )
    {
      // Zähler erhöhen
      charCounter++;

      // Wenn mehr als 3 Grundzahlen nebeneinander
      if ( charType == 1 && charCounter == 3)
      {
        printComment( "Verstoß gegen Regel 1: es dürfen höchstens 3 Grundzahlen (hier '"
                    + romanNumber.charAt(i - 1) + "') nebeneinander stehen." );
      }

      // Wenn mehr als 1 Zwischenzahl hintereinander
      if ( charType == 0 && charCounter == 1)
      {
        printComment( "Verstoß gegen Regel 1: ein und die selbe Zwischenzahl (hier '"
                    + romanNumber.charAt(i - 1) + "') darf nicht direkt hintereinander stehen." );
        return 0;
      }
    }
    else
    {
      charCounter = 0;
    }

    // Dezimalzahl erhöhen
    decimalNumber += curValancy;

    // alte Wertigkeit merken
    oldValancy = curValancy;

    // Wenn eine subtraktive Kombination
    // maximale Wertigkeit ermitteln (aus der aktuellen Ziffer)
    // und eine Stelle überspringen
    if( charType == 2 )
    {
      maxValancy = romanValancy(romanNumber.charAt(i))
      i++;
    }
  }

  return decimalNumber;
}

// Dezimal nach römisch
function decimal2roman()
{
  initComment();


  var decimalNumber = document.getElementById('decimal').value;

  // ist die Zahl zu groß
  if( decimalNumber > 3999 )
  {
    printComment("Fehler: Die höchste Zahl im römischen Zahlensystem ist 3999.");
    document.romanForm.decimal.value = "3999";
    return;
  }

  // kurze Darstellung
  var romanNumberShort  = decimal2romanShort(decimalNumber);

  // lange Darstellung
  var romanNumberLong   = decimal2romanLong (decimalNumber);

  // lange Darstellung übernehmen
  document.getElementById('roman').value = romanNumberLong;
}
