/**
 * Oppgave9_1.java - "Programmering i Java", 4.utgave - 2010-02-22
 *
 */
import static javax.swing.JOptionPane.*;

/**
 * Klassen Prisliste
 * Prisliste mer varenr fra og med 1000.
 * Listen inneholder kun prisen på den enkelte vare identifisert med varenummeret.
 */
class Prisliste{
  private double[] liste = new double[2];  // liten for testformål
  private int antallRegistrert = 0;
  private final int TILLEGG = 1000; // varenr = indeksen + TILLEGG

  /**
   * Metoder for å finne min. og maks. varenummer
   */
  public int finnMinVarenr() {
    return finnVarenr(0);
  }

  public int finnMaksVarenr() {
    return finnVarenr(antallRegistrert - 1);
  }

  /**
   * Returnerer prisen på en vare gitt varenummeret.
   * Hvis ugylsig varenummer, returneres negativt tall.
   */
  public double finnPris(int vareNr) {
    int indeks = finnIndeks(vareNr);
    return gyldigIndeks(indeks) ? liste[indeks] : -1;
  }

  /**
   * Returnerer antall registrerte varer.
   */
  public int finnAntallRegistrert() {
    return antallRegistrert;
  }

  /**
   * Setter ny pris på en vare med gitt nummer.
   * Metoden returnerer false dersom ugyldig varenummer, ellers true.
   */
  public boolean settNyPris(int vareNr, double pris) {
    int indeks = finnIndeks(vareNr);
    if (gyldigIndeks(indeks)) {
      liste[indeks] = pris;
      return true;
    }
    return false;
  }

  /**
   * Registrerer en ny vare.
   * Varenummeret returneres.
   */
  public int registrerNyVare(double pris) {
    if (antallRegistrert == liste.length) {  // tabellen er full, må utvide
      utvidTabell();
    }
    liste[antallRegistrert] = pris;
    antallRegistrert++;
    return finnVarenr(antallRegistrert - 1);
  }

  /**
   * Endrer prisen på en vare med et gitt antall prosent.
   * Metoden returnerer den nye prisen, eventuelt negativt tall hvis ugyldige varenr.
   */
  public double endrePrisProsent(int vareNr, double prosent) {
    int indeks = finnIndeks(vareNr);
    if (gyldigIndeks(indeks)) {
      liste[indeks] += (liste[indeks] * prosent) / 100.0;
      return liste[indeks];
    }
    return -1.0;
  }

  /**
   * toString(), skriver ut varenummer og pris for alle varene.
   */
  public String toString() {
    java.util.Formatter f = new java.util.Formatter();
    for (int i = 0; i < antallRegistrert; i++) {
      f.format("\nVare nr. %d koster NOK %.2f.", finnVarenr(i), liste[i]);
    }
    return f.toString();
  }

  /**
   * Hjelpemetoder ...
   */
  private void utvidTabell() {
    double[] nyTab = new double[liste.length + 3];
    for (int i = 0; i < liste.length; i++) {
      nyTab[i] = liste[i];
    }
    liste = nyTab;
  }

  private int finnIndeks(int varenr) {
    return varenr - TILLEGG;
  }

  private int finnVarenr(int indeks) {
    return indeks + TILLEGG;
  }

  private boolean gyldigIndeks(int indeks) {
    return indeks >= 0 && indeks < antallRegistrert;
  }
}

/**
 * Klasse for brukerkommunikasjon.
 */
class VareBGS {

  /* Konstanter til bruk i menyen */
  private final String[] ALTERNATIVER = {"Registrer ny vare",
  "Ny pris på en vare", "Finn prisen på en vare", "Endre prisen i prosent", "Avslutt"};
  private final int REG_VARE = 0;   // tallverdiene svarer til indeksen i tabellen over
  private final int NY_PRIS = 1;
  private final int FINN_PRIS = 2;
  private final int ENDRE_PRIS_PROSENT = 3;
  private final int AVSLUTT = 4;

  private Prisliste liste;  // Objektet vi skal kommuniser med
  public VareBGS(Prisliste liste) {
    this.liste = liste;
  }

  /**
   * Viser menyen som er rekke trykknapper.
   * Metoden returnerer brukerens valg som en indeks i tabellen ALTERNATIVER.
   * Hvis brukeren vil avslutte, returneres en negativ verdi.
   */
  public int lesValg() {
    int valg = showOptionDialog(null, "Gjør et valg", "Prisliste", DEFAULT_OPTION,
                PLAIN_MESSAGE, null, ALTERNATIVER, ALTERNATIVER[0]);
    if (valg == AVSLUTT) {
      valg = -1;
    }
    return valg;
  }

  /**
   * Hovedflyt for utførelse av valgt oppgave.
   */
  public void utførValgtOppgave(int valg) {
      switch (valg) {
      case REG_VARE:
        registrerNyVare();
        break;
      case NY_PRIS:
        settNyPris();
        break;
      case FINN_PRIS:
        finnPris();
        break;
      case ENDRE_PRIS_PROSENT:
        endrePrisProsent();
        break;
      default:
        break;
    }
  }

  /**
   * Registrerer en ny vare.
   *
   * Innlesing fra brukeren: Prisen.
   * Utskrift: Varenummeret.
   */
  public void registrerNyVare() {
    double pris = lesDesimaltall( "Oppgi prisen på den nye varen: ");
    int varenr = liste.registrerNyVare(pris);
    showMessageDialog(null, "Varen er registrert med varenummer " + varenr);
    System.out.println(liste.toString());
  }

  /**
   * Setter ny pris på en vare.
   * Innlesing fra brukeren: Varenummer.
   * Utskrift: Bekreftelse, eventuelt feilmelding.
   */
  public void settNyPris() {
    if (liste.finnAntallRegistrert() == 0) {
      showMessageDialog(null, "Ingen varer registrert.");
      return;
    }
    int min = liste.finnMinVarenr();
    int maks = liste.finnMaksVarenr();
    int varenr = lesHeltall( "Oppgi varenr (min " + min + ", maks " + maks + ")", min, maks);
    double nyPris = lesDesimaltall("Den nye prisen: ");
    if (liste.settNyPris(varenr, nyPris)) {
      showMessageDialog(null, "Ny pris registrert.");
    } else {
      showMessageDialog(null, "Ugyldig varenummer.");
    }
    System.out.println(liste.toString());
  }

  /**
   * Finner prisen på en bestemt vare.
   *
   * Innlesing fra brukeren: Varenummer.
   * Utskrift: Prisen, eventuelt feilmelding.
   */
  public void finnPris() {
    if (liste.finnAntallRegistrert() == 0) {
      showMessageDialog(null, "Ingen varer registrert.");
      return;
    }
    int min = liste.finnMinVarenr();
    int maks = liste.finnMaksVarenr();
    int varenr = lesHeltall( "Oppgi varenr (min " + min + ", maks " + maks + ")", min, maks);
    double pris = liste.finnPris(varenr);
    if (pris >= 0) {
      java.util.Formatter f = new java.util.Formatter();
      f.format("Prisen på vare nr %d er NOK %.2f.", varenr, pris);
      showMessageDialog(null, f.toString());
    } else {
      showMessageDialog(null, "Ugyldig varenummer.");
    }
    System.out.println(liste.toString());
  }

  /**
   * Endrer prisen på en bestemt vare.
   *
   * Innlesing fra brukeren: Varenummer og prosentendring.
   * Utskrift: Ny pris, eventuelt feilmelding.
   */
  public void endrePrisProsent() {
    if (liste.finnAntallRegistrert() == 0) {
      showMessageDialog(null, "Ingen varer registrert.");
      return;
    }
    int min = liste.finnMinVarenr();
    int maks = liste.finnMaksVarenr();
    int varenr = lesHeltall("Oppgi varenr (min " + min + ", maks " + maks + ")", min, maks);
    double prosent = lesDesimaltall("Endring i prosent");
    double nyPris = liste.endrePrisProsent(varenr, prosent);
    if (nyPris >= 0) {
      java.util.Formatter f = new java.util.Formatter();
      f.format("Ny prisen på vare nr %d er NOK %.2f.", varenr, nyPris);
      showMessageDialog(null, f.toString());
    } else {
      showMessageDialog(null, "Ugyldig varenummer.");
    }
    System.out.println(liste.toString());
  }

  /*
   * Hjelpemetode. Leser inn et heltall som må ligge innenfor et lukket intervall.
   * Parametere:
   *   ledetekst: Ledeteksten som skrives til brukeren, den bør inneholde informasjon om intervallet.
   *   nedre: Nedre gyldige verdi.
   *   øvre: Øvre gyldige verdi.
   */
  private int lesHeltall(String ledetekst, int nedre, int øvre) {
    String tallLest = showInputDialog(ledetekst);
    int tall = Integer.parseInt(tallLest);
    while (tall < nedre || tall > øvre) {
      tallLest = showInputDialog("Tallet du skriver må være større eller lik " + nedre
                                   + " og mindre eller lik " + øvre + ". \nPrøv på nytt: ");
      tall = Integer.parseInt(tallLest);
    }
    return tall;
  }

  private double lesDesimaltall(String ledetekst) {
    String tallLest = showInputDialog(ledetekst);
    return Double.parseDouble(tallLest);
  }
}

class Oppgave9_1 {
  public static void main(String[] args) {

    Prisliste liste = new Prisliste();
    VareBGS bgs = new VareBGS(liste);

    int valg = bgs.lesValg();
    while (valg >= 0) {
      bgs.utførValgtOppgave(valg);
      valg = bgs.lesValg();
    }
  }
}