/************************************************************************
 * Rgb.java                                                              *
 * Bearbeitung: Rainer Bugl                                              *
 * MatNr.     : 0126574                                                  *
 *                                                                       *
 * Runde 3                                                               *
 * BspNr: 3055                                                           *
 * Klasse: schwer                                                        *
 *                                                                       *
 * Beschreibung der Aufgabenstellung:                                    *
 * Ein Farbwert im RGB-Farbwürfel soll auf einen Farbwürfel mit 147      *
 * Farbwerten abgebildet werden. Das entspricht einem Reduktionsver-     *
 * hältnis von 256:256:256 zu 7:7:3. Die Farbgrenzen sollen gerundet     *
 * werden und für alle 8-Eckpunkte soll der normierte Abstand zum        *
 * eingegebenen Punkt errechnet werden.                                  *
 *                                                                       *
 * Die einzige Abweichung zur Original-Aufgabenstellung war:             *
 * a) nicht SHORT sondern INTEGER werden als Eingabe erwartet            *
 * b) anstatt der Ausgabe nächstgelegener und entferntester Punkt        *
 *  -> den normierten Abstand je Eckpunkt zu liefern                     *
 * c) die Ausgabe der Eckpunkte in aufsteigender Sortierung              *
 *                                                                       *
 * Das Programm "farb1.java" von Stefan Ehmann konnte komplett ver-      *
 * wendet werden. Es wurde nur um die Funktionalität der "Sortierung"    *
 * und, zur Erleichterung der Tests, mit einer "Debug"-Funktion ausge-   *
 * stattet.                                                              *
 *                                                                       *
 * Für weitere Erklärung siehe ... Rgb.txt                               *
 *                                                                       *
 *                                                                       *
 * ACHTUNG! Um die "Debug"-Funktion zu aktivieren ist nur die Konstante  *
 *          dbgOn auf den Wert true zu stellen.                          *
 *                                                                       *
 * ORIGINAL ------------------------------------------------------------ *
 * farb1.java                                                            *
 *                                                                       *
 * Autor: Stefan Ehmann                                                  *
 * MatNr: 0125637                                                        *
 *                                                                       *
 * Runde 1                                                               *
 * BspNr: 1200                                                           *
 * Klasse: schwer                                                        *
 *                                                                       *
 * Beschreibung:                                                         *
 * Ein Farbwert im RGB-Farbwürfel (Rot, Grün, Blau je 256 Stufen) soll   *
 * auf einen von 256 Farbwerten abgebildet werden                        *
 ************************************************************************/

// reformated with idea (www.intellij.com) by heder

import eprog.EprogException;
import eprog.EprogIO;

// Klasse Rgb, Hauptklasse mit main-Methode

public class Rgb extends EprogIO
{
  // DEBUG-Schalter, false=ohne zusaetzliche Ausgaben
  private static final boolean dbgOn = false;

  // main, Hauptprogramm
  public static void main(String[] args)
  {
    try
    {
      // Einlesen der Eingabewerte
      int rValue = readInt();
      int gValue = readInt();
      int bValue = readInt();

      // Eingabewerte in einem RgbValue-Objekt speichern
      RgbValue Eingabe = new RgbValue(rValue, gValue, bValue);

      // Einteilung des RGB-Würfels in Quader

      int rgBorder[] = new int[8]; // Grenzen auf der R- und G-Achse
      int bBorder[] = new int[4]; // Grenzen auf der B-Achse

      // Um bei ROT und GRÜN 8 Abstufungen zu erhalten,
      // dividiere die 256 Werte durch 7
      // runde das Ergebnis auf ganze Zahlen
      for (int i = 0; i < 8; i++)
      {
        rgBorder[i] = (int) Math.round((float) 255 * (i) / 7);
      }

      // Um bei BLAU 4 Abstufungen zu erhalten,
      // dividiere die 256 Werte durch 3
      // runde das Ergebnis auf ganze Zahlen
      for (int i = 0; i < 4; i++)
      {
        bBorder[i] = (int) Math.round((float) 255 * (i) / 3);
      }

      // Ermittle die untere und obere Grenze des Quaders,
      // in dem der RGB Wert liegt
      // Um die Grenzen zu erhalten vergleiche die einzelnen R, G und
      // B-Werte mit den Grenzen

      // Berechnung der Grenzen für die R-Koordinate
      int val = 1;
      while (rgBorder[val] < Eingabe.red)
        val++;
      int rLo = rgBorder[val - 1];    //  untere R-Grenze
      int rHi = rgBorder[val];  // obere R-Grenze

      // Berechnung der Grenzen für die G-Koordinate
      val = 1;
      while (rgBorder[val] < Eingabe.green)
        val++;
      int gLo = rgBorder[val - 1];    // untere G-Grenze
      int gHi = rgBorder[val];  // obere G-Grenze

      // Berechnung der Grenzen für die B-Koordinate
      val = 1;
      while (bBorder[val] < Eingabe.blue)
        val++;
      int bLo = bBorder[val - 1]; // untere B-Grenze
      int bHi = bBorder[val];   // obere B-Grenze

      // Eckpunkte des Quaders berechnen und als RgbValue-Objekte speichern
      RgbValue Corners[] = new RgbValue[8];
      Corners[0] = new RgbValue(rLo, gLo, bLo);
      Corners[1] = new RgbValue(rLo, gLo, bHi);
      Corners[2] = new RgbValue(rLo, gHi, bLo);
      Corners[3] = new RgbValue(rLo, gHi, bHi);
      Corners[4] = new RgbValue(rHi, gLo, bLo);
      Corners[5] = new RgbValue(rHi, gLo, bHi);
      Corners[6] = new RgbValue(rHi, gHi, bLo);
      Corners[7] = new RgbValue(rHi, gHi, bHi);

      // berechnet die Entfernung zwischen Eckpunkt und Eingabe
      // und ermittelt die Summe aller Abstaende
      double distance[][] = new double[8][2];
      double sumDistance = 0;
      for (int i = 0; i < 8; i++)
      {
        distance[i][0] = Eingabe.distance(Corners[i]);
        sumDistance += distance[i][0];
      }

      // berechnet den "normierten Abstand"
      for (int i = 0; i < 8; i++)
        distance[i][1] = distance[i][0] / sumDistance;

      // "normierten Abstand" sortieren
      dSort2D(distance);

      // DEBUG: Punkte mit ermittelten "normierten Abstand" ausgeben
      if (dbgOn)
        dbgDistance(Corners, distance);

      // normierten Abstand aller 8-Kanten ausgeben
      for (int i = 0; i < 8; i++)
      {
        printFixed(distance[i][1]);
        if (i < 7)
          print(" "); // mit Leerzeichen trennen
      }
      println(); // mit Zeilenvorschub abschliessen
    }

            // Ausnahmebehandlung
    catch (EprogException E)
    {
      // bei falschem Datentyp '?' ausgeben
      if (E.getMessage().equals("Wrong Datatype: Not an Integer"))
        println("?");
      else    // ansonsten benutzerdefinierte Fehlermeldung
        println(E.getMessage());
    }
  }

  // Sortieren einer 2Dimensionalen-Tabelle mittels Bubble-Sort
  public static void dSort2D(double sortTab[][])
  {
    for (int i = sortTab.length - 1; i >= 0; i--)
    {
      for (int ii = 1; ii <= i; ii++)
      {
        // ... Werte vertauschen
        if (sortTab[ii - 1][1] > sortTab[ii][1])
        {
          double tmp0 = sortTab[ii - 1][0];
          double tmp1 = sortTab[ii - 1][1];
          sortTab[ii - 1][0] = sortTab[ii][0];
          sortTab[ii - 1][1] = sortTab[ii][1];
          sortTab[ii][0] = tmp0;
          sortTab[ii][1] = tmp1;
        }
      }
    }
  }

  // DEBUG: Punkte mit ermittelten "normierten Abstand" ausgeben
  public static void dbgDistance(RgbValue Corners[], double distance[][])
  {
    // Eckpunkte und normierten Abstand ausgeben
    println();
    println("Eckpunkte mit normierten Abstand");
    for (int i = 0; i < 8; i++)
    {
      print(Corners[i].red);
      print("\t");
      print(Corners[i].green);
      print("\t");
      print(Corners[i].blue);

      print("\t(");
      printFixed(distance[i][0]);
      print(")");

      print("\t");
      if (distance[i][1] == 0.0)
        print("\t");
      printFixed(distance[i][1]);
      println();
    }
    println();
  }
}

// Klasse RgbValue speichert einen 24-Bit RGB-Wert und definiert die
// Methoden equals() und distance()

class RgbValue
{
  // Konstruktor initialisiert die Member-Variablen red, green und blue
  RgbValue(int rv, int gv, int bv) throws EprogException
  {
    // Überprüfung der Werte
    // Zahl muss zwischen 0 und 255 liegen
    // wenn außerhalb des gültigen Wertebereichs, werfe Ausnahme
    if (rv < 0 || rv > 255 || gv < 0 || gv > 255 || bv < 0 || bv > 255)
      throw new EprogException("FALSCHE EINGABE");

    red = rv;
    green = gv;
    blue = bv;
  }

  // equals() vergleicht das aktuelle Objekt mit R
  // gibt true zurück, falls beide Objekte komponentenweise gleich sind
  // andernfalls false
  boolean equals(RgbValue R)
  {
    return (red == R.red && green == R.green && blue == R.blue);
  }

  // distance() berechnet den Abstand zwischen dem aktuellen Objekt und
  // dem Objekt Rv nach der Formel für den Betrag eines Vektors im Raum
  double distance(RgbValue Rv)
  {
    return Math.sqrt(
            (Rv.red - red) * (Rv.red - red) +
            (Rv.green - green) * (Rv.green - green) +
            (Rv.blue - blue) * (Rv.blue - blue)
    );
  }

  int red;
  int green;
  int blue;
}