/* Autor: Stephan Kleuker
 * Version 1.0 16.10.2009
 * Hinweis: Die hier gezeigten Klassen sind als einführende
 * Beispiele in die JPA-Funktionalität gedacht. Bei größeren
 * Systemen muss über eine Aufteilung der Funktionalität in mehrere
 * Schichten nachgedacht werden.
 */
package jpa20beispielanfragen;

import java.util.Collection;
import java.util.Iterator;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import jpa20beispielanfragen.entities.Mitarbeiter;
import jpa20beispielanfragen.entities.Projekt;
import jpa20beispielanfragen.entities.Projektauftrag;
import jpa20beispielanfragen.entities.Rolle;

public class Main {

  private EntityManagerFactory eMF =
          Persistence.createEntityManagerFactory("JPA20BeispielAnfragenPU");
  private EntityManager em = eMF.createEntityManager();

  /* Einspielen der Daten aus der Vorlesung */
  public void beispieldaten() {
    Projekt p1 = new Projekt("Bonitaet");
    Projekt p2 = new Projekt("Bremse");
    Rolle r1 = new Rolle("Java", 60);
    Rolle r2 = new Rolle("C", 50);
    Rolle r3 = new Rolle("Cobol", 70);
    Mitarbeiter m1 = new Mitarbeiter("Ivan");
    Mitarbeiter m2 = new Mitarbeiter("Fatma");
    Mitarbeiter m3 = new Mitarbeiter("Urs");
    Mitarbeiter m4 = new Mitarbeiter("Heinz");
    Projektauftrag pa[] = {new Projektauftrag("Historie"),
      new Projektauftrag("Konten"),
      new Projektauftrag("Raten"),
      new Projektauftrag("Sensoren"),
      new Projektauftrag("Fusion"),
      new Projektauftrag("Display")};
    for (int i = 0; i < 3; i++) {
      p1.projektauftragHinzu(pa[i]);
      p2.projektauftragHinzu(pa[i + 3]);
    }
    m1.rolleHinzu(r1);
    r1.mitarbeiterHinzu(m1);
    m1.rolleHinzu(r2);
    r2.mitarbeiterHinzu(m1);

    m2.rolleHinzu(r1);
    r1.mitarbeiterHinzu(m2);
    m2.rolleHinzu(r3);
    r3.mitarbeiterHinzu(m2);

    m3.rolleHinzu(r1);
    r1.mitarbeiterHinzu(m3);
    m4.rolleHinzu(r2);
    r2.mitarbeiterHinzu(m4);

    pa[0].setRolle(r1);
    pa[1].setRolle(r3);
    pa[2].setRolle(r1);
    pa[3].setRolle(r2);
    pa[4].setRolle(r2);
    pa[5].setRolle(r1);

    pa[0].setBearbeiter(m3);
    m3.auftragHinzu(pa[0]);
    pa[1].setBearbeiter(m2);
    m2.auftragHinzu(pa[1]);
    pa[2].setBearbeiter(m1);
    m1.auftragHinzu(pa[2]);
    pa[3].setBearbeiter(m1);
    m1.auftragHinzu(pa[3]);
    pa[4].setBearbeiter(m1);
    m1.auftragHinzu(pa[4]);
    pa[5].setBearbeiter(m2);
    m2.auftragHinzu(pa[5]);

    Object o[] = {m1, m2, m3, m4, p1, p2};

    em.getTransaction().begin();
    for (int i = 0; i < o.length; i++) {
      em.persist(o[i]);
    }
    em.getTransaction().commit();

  }

  /* Hilfsabfrage ob Tabelle tabelle existiert */
  public boolean existenzPruefen(String tabelle) {
    try {
      em.createQuery("SELECT o FROM " + tabelle + " o");
      return true;
    } catch (IllegalArgumentException e) {
      return false;
    }
  }

  /* Interaktives Anfragewerkzeug, Anfragen über mehrere Zeilen
   * möglich. Am Ende der Abfrage muss ein Semikolon stehen. */
  public void anfragen() {
    String anfrage = "";
    while (!anfrage.toUpperCase().equals("ENDE ")) {
      anfrage = "";
      System.out.println("Anfrage eingeben (Programmende mit ENDE, "
              + "am Anfrageende ein ;)");
      while (!anfrage.toUpperCase().equals("ENDE ") && !anfrage.endsWith("; ")) {
        anfrage += Eingabe.leseString() + " ";
      }
      if (!anfrage.toUpperCase().equals("ENDE ")) {
        anfrage = anfrage.substring(0, anfrage.length() - 2);
        try {
          Query query = em.createQuery(anfrage);
          Collection erg = query.getResultList();
          for (Iterator it = erg.iterator(); it.hasNext();) {
            System.out.println(it.next());
          }
        } catch (Exception e) {
          System.out.println("Anfrage gescheitert: " + e.getMessage());
        }
        anfragen2(anfrage); // nur sinnvoll, wenn Array als Ergebnis
      }
    }
  }

  /* Ausführung der Anfrage ql, für die eine "normale" Liste von
   * Objekten als Ergebnis erwartet wird. */
  public void anfragen(String ql) {
    System.out.println(ql);
    try {
      Query query = em.createQuery(ql);
      Collection erg = query.getResultList();
      for (Iterator it = erg.iterator(); it.hasNext();) {
        System.out.println(it.next());
      }
    } catch (Exception e) {
      System.out.println("Anfrage gescheitert: " + e.getMessage());
    } finally {
      System.out.println("-------------------");
    }
  }

  /* Detailliertere Analyse des Ergebnisses der Anfrage ql, falls
   * Object-Arrays in der Ergebnisliste stehen, werden Elemente der
   * Arrays einzeln ausgegeben. */
  public void anfragen2(String ql) {
    System.out.println(ql);
    try {
      Query query = em.createQuery(ql);
      Collection erg = query.getResultList();
      for (Iterator it = erg.iterator(); it.hasNext();) {
        Object o = it.next();
        System.out.println(o + " :: " + o.getClass().getName());
        if (o.getClass().getName().equals("[Ljava.lang.Object;")) {
          Object oa[] = (Object[]) o;
          for (int i = 0; i < oa.length; i++) {
            System.out.println("  " + oa[i]);
          }
        }
      }
    } catch (Exception e) {
      System.out.println("Anfrage gescheitert: " + e.getMessage());
    }
  }

  public void anzeigen() {
    String entitaeten[] = {"Mitarbeiter", "Projektauftrag", "Projekt", "Rolle"};
    for (int i = 0; i
            < entitaeten.length; i++) {
      String anfrage = "SELECT o FROM " + entitaeten[i] + " o";
      Query query = em.createQuery(anfrage);
      Collection erg = query.getResultList();
      System.out.println(entitaeten[i]);
      for (Iterator it = erg.iterator(); it.hasNext();) {
        System.out.println(it.next());
      }

    }
  }

  public void projektVon(String name) {
    anfragen("SELECT p.name FROM Projekt p JOIN p.auftraege pa "
            + "WHERE pa.bearbeiter.name='" + name + "'");
  }

  /* nur zu Demozwecken als Variante */
  private static final String PROJEKT_VON =
          "SELECT p.name FROM Projekt p JOIN p.auftraege pa "
          + "WHERE pa.bearbeiter.name= :mname";

  public void projektVon2(String name) {
    Query query = em.createQuery(PROJEKT_VON).setParameter("mname", name);
    Collection erg = query.getResultList();
    for (Iterator it = erg.iterator(); it.hasNext();) {
      System.out.println(it.next());
    }
  }

  public void zeigeMitarbeiter(int minr) {
    System.out.println(Mitarbeiter.zuMinr(minr, em));
    Mitarbeiter m = em.createNamedQuery("Mitarbeiter.primaryKey", Mitarbeiter.class).
            setParameter("minr", minr).getSingleResult();
  }

  public void zeigeMAMitFaehigkeiten(String faehigkeit) {
    System.out.println(" :: " + faehigkeit);
    for (Mitarbeiter m : em.createNamedQuery("Mitarbeiter.mitFaehigkeit", Mitarbeiter.class).
            setParameter("name", faehigkeit).getResultList()) {
      System.out.println(m);
    }
  }

  public void schliessen() {
    if (em != null && em.isOpen()) {
      em.close();
    }
    if (eMF != null && eMF.isOpen()) {
      eMF.close();
    }
  }

  public void ooartigeAnfragekonstruktion() {
    CriteriaBuilder qB = em.getCriteriaBuilder();
    CriteriaQuery<Mitarbeiter> cQ = qB.createQuery(Mitarbeiter.class);
    Root<Mitarbeiter> mAlias = cQ.from(Mitarbeiter.class);
    cQ.where(qB.notEqual(mAlias.get("name"), "Urs"));
    TypedQuery<Mitarbeiter> tq = em.createQuery(cQ);
    for (Mitarbeiter m : tq.getResultList()) {
      System.out.println(m.getName());
    }
  }

  public static void main(String[] args) {
    Main jpa = new Main();

    jpa.beispieldaten();

    jpa.anzeigen();
    System.out.println(jpa.existenzPruefen("Mitarbeiter"));
    System.out.println(jpa.existenzPruefen("Miarbeiter"));


    jpa.anfragen("SELECT p FROM Projekt p");
    jpa.anfragen("SELECT p.name FROM Projekt p");

    jpa.anfragen("SELECT p.auftraege.bearbeiter FROM Projekt p");

    jpa.anfragen("SELECT pa.bearbeiter FROM Projektauftrag pa");

    jpa.anfragen2("SELECT r.name, r.tagessatz FROM Rolle r");

    jpa.anfragen("SELECT m.name "
            + "FROM Projektauftrag pa, Mitarbeiter m "
            + "WHERE pa.bearbeiter=m"
            + "  AND pa.titel='Sensoren'");

    jpa.anfragen("SELECT m.name "
            + "FROM Projektauftrag pa JOIN pa.bearbeiter m "
            + "WHERE pa.titel='Sensoren'");

    jpa.anfragen("SELECT DISTINCT(pa.bearbeiter.name) "
            + "FROM Projekt p JOIN p.auftraege pa "
            + "  WHERE p.name='Bremse'");

    jpa.anfragen("SELECT p.name "
            + "FROM Projekt p JOIN p.auftraege pa "
            + "WHERE pa.bearbeiter.name='Urs'");
    jpa.anfragen("SELECT p.name "
            + "FROM Projekt p JOIN p.auftraege pa "
            + "WHERE pa.bearbeiter.name='Urs' OR NOT (p.name='bla')");

    jpa.projektVon("Urs");
    jpa.projektVon("Urs' OR NOT(p.name='bla') OR p.name='bla");

    jpa.projektVon2("Urs");
    jpa.projektVon2("Urs' OR NOT (p.name!='bla') OR p.name='blaENDE");

    //jpa.zeigeMAMitFaehigkeiten("C");
    //jpa.zeigeMitarbeiter(2);

    System.out.println("----");
    jpa.ooartigeAnfragekonstruktion();

    jpa.anfragen();
    jpa.schliessen();
  }
}
