/**
 * Oppgave9_3.java  - "Programmering i Java", 4.utgave - 2010-02-22
 * Løsningen bygger på en løsning utviklet av Simon Toresen fra 1.utgave av boka (år 2000).
 *
 * En klasse Matrise som implementerer en matematisk matrise med tilhørende metoder.
 * Konstruktøren oppretter matrisen og fyller den med nuller.
 * Metoden settVerdi() brukes for å fylle matrisen med tall.
 *
 */

/**
 * Klassen Matrise
 */
class Matrise {
  private double verdier[][];

  public Matrise(int antRader, int antKolonner) {
    verdier = new double[antRader][];
    for (int i = 0; i < antRader; i++) {
      verdier[i] = new double[antKolonner];
      for (int j = 0; j < antKolonner; j++) {
        verdier[i][j] = 0.0;
      }
    }
  }

  /**
   * Finnmetoder
   */
  public int finnAntRader() {
    return verdier.length;
  }

  public int finnAntKolonner() {
    return verdier[0].length;
  }

  public double finnVerdi(int rad, int kolonne) throws ArrayIndexOutOfBoundsException {
    return verdier[rad][kolonne];
  }

  /**
   * Settmetoder
   */
  public void settVerdi(int rad, int kolonne, double verdi) throws ArrayIndexOutOfBoundsException {
    verdier[rad][kolonne] = verdi;
  }

  /**
   * Andre metoder
   */

  /**
   * Adderer to matriser.
   * Metoden returnerer en ny matrise som er summen av this-matrisen og argument-matrisen.
   * Hvis matrisene ikke kan summeres (dvs. at antall rader og/eller kolonner ikke stemmer)
   * returneres null.
   */
  public Matrise adder(Matrise matrise) {

    /* Kontrollerer at kravene til addisjon er oppfylt */
    if (matrise.finnAntRader() != finnAntRader() || matrise.finnAntKolonner() != finnAntKolonner()) { // ikke ok
      return null;
    }

    Matrise sum = new Matrise(finnAntRader(), finnAntKolonner());
    for (int i = 0; i < finnAntRader(); i++) {
      for (int j = 0; j < finnAntKolonner(); j++) {
        sum.settVerdi(i, j, verdier[i][j] + matrise.finnVerdi(i, j));
      }
    }
    return sum;
  }

  /**
   * Adderer to matriser.
   * Metoden returnerer en ny matrise som er produktet av this med argumentet.
   * Hvis matrisene ikke kan multipliseres (dvs. at antall rader i this-matrisen ikke er lik antall kolonner
   * i argumentmatrisen) returneres null.
   */
  public Matrise multipliser(Matrise matrise) {
    /* Kontrollerer at kravene til multiplikasjon er oppfylt */
    if (matrise.finnAntRader() != finnAntKolonner()) { // ikke ok
      return null;
    }

    Matrise sum = new Matrise(finnAntRader(), matrise.finnAntKolonner());

    for (int i = 0; i < finnAntRader(); i++) {
      for (int j = 0; j < finnAntKolonner(); j++) {
        for (int k = 0; k < finnAntKolonner(); k++) {
          sum.settVerdi(i, j, sum.finnVerdi(i, j) + verdier[i][k] * matrise.finnVerdi(k, j));
        }
      }
    }
    return sum;
  }

  public Matrise transponer() {
    Matrise resultat = new Matrise(finnAntKolonner(), finnAntRader());
    for (int i = 0; i < finnAntRader(); i++) {
      for (int j = 0; j < finnAntKolonner(); j++) {
        resultat.settVerdi(j, i, verdier[i][j]);
      }
    }
    return resultat;
  }

  public String toString() {
    StringBuilder str = new StringBuilder(); // som eksempel, mer effektivt enn String
    for (int i = 0; i < finnAntRader(); i++) {
      for (int j = 0; j < finnAntKolonner(); j++) {
        str.append(verdier[i][j] + "\t");
      }
      str.append("\n");
    }
    return str.toString();
  }
}

public class Oppgave9_3 {
  public static void main(String[] args) {

    /* Oppretter to matriser */
    Matrise matrise1 = new Matrise(3, 2);
    Matrise matrise2 = new Matrise(2, 2);

    /* Ingen kontroll på returverdiene fra settVerdi() */
    matrise1.settVerdi(0, 0, 4.0);
    matrise1.settVerdi(0, 1, 3.0);
    matrise1.settVerdi(1, 0, 7.0);
    matrise1.settVerdi(1, 1, 2.0);
    matrise1.settVerdi(2, 0, 9.0);
    matrise1.settVerdi(2, 1, 0.0);

    matrise2.settVerdi(0, 0, 2.0);
    matrise2.settVerdi(0, 1, 5.0);
    matrise2.settVerdi(1, 0, 1.0);
    matrise2.settVerdi(1, 1, 6.0);

    /* Prøver de forskjellige metodene i klassen Matrise. */
    System.out.println("Matrise 1:\n" + matrise1.toString());
    System.out.println("\nMatrise 2:\n" + matrise2.toString());

    Matrise sum = matrise1.adder(matrise2);
    if (sum != null) {
      System.out.println("\nMatrisesum:\n" + sum.toString());
    } else {
      System.out.println("\nIkke mulig å summere matrisene.");
    }
    Matrise produkt = matrise1.multipliser(matrise2);
    if (produkt != null) {
      System.out.println("\nMatriseprodukt:\n" + produkt.toString());
    } else {
      System.out.println("\nIkke mulig å multiplisere matrisene.");
    }
    Matrise transponert = matrise1.transponer();
    System.out.println("\nMatrise 1 transponert:\n" + transponert.toString());
  }
}

/* Utskriftvindu:
Matrise 1:
4.0     3.0
7.0     2.0
9.0     0.0


Matrise 2:
2.0     5.0
1.0     6.0


Ikke mulig å summere matrisene.

Matriseprodukt:
11.0    38.0
16.0    47.0
18.0    45.0


Matrise 1 transponert:
4.0     7.0     9.0
3.0     2.0     0.0
*/