//Autor:        Philipp Muigg
//MatrikelNr:   0125958
//e-mail:       p.muigg@kabsi.at
//Beispielname: Konvneck (konvexes Vieleck)
//BeispielNr: 3254

import TVerglZuwObj;
import TKoo2d;

public class TPolygon implements TVerglZuwObj
{
//math konstanten
//bitbedeutung: bit1: gesetzt wenn konvex
//              bit2: gesetzt wenn konkav
//              bit3: gesetzt wenn schneidend
//              bit4: gesetzt wenn invalid
//(ich weiß daß das ein wenig umständlich klingt... war halt ein wenig herum=
//probieren mit maskieren, demaskiereun usw :) )
  public final static int POLYSTAT_KONVEX =0x1;
  public final static int POLYSTAT_KONKAV =0x2;
  public final static int POLYSTAT_INVALID =0x8;
  public final static int POLYSTAT_SCHNEIDET=0x4;
  //public final static int POLYSTAT_SCHNEIDETNICHT=0x0;

//fehler wird von den Konstruktoren auf true gesetzt wenn probleme beim inizialisieren
//der Daten aufgetreten sind.
  private boolean fehler;
//speicherobjekt für die Koordinaten der eckpunkte (siehe TArrayAppendObj.java für weitere information)
  private TArrayAppendObj punkteArray;
//array von TLinie Objekten, das alle Kanten des Polygons beinhaltet
  private TLinie[] kantenArray;

//Math methoden
//testet ob alle Koordinaten innerhalb gewisser grenzen liegen (laut spez vorgeschrieben)
  public boolean sindKoosIn (double lower, double upper)
  {
    for (int i=0; i<=punkteArray.getObjZahl();i++)
    {
      if ((getPunkt(i).getX()<lower)||(getPunkt(i).getX()>upper)||(getPunkt(i).getY()<lower)||(getPunkt(i).getY()>upper))
        return false;
    }
    return true;
  }
//der hier angewendete algorithmus zur bestimmung des polygonstatus (ob konvex, konkav)
//ist in der spez angegeben.
  public int getPolystat()
  {
//falls der polygon bereits bei der inizialisierung fehlerhaft war ist er invalid
    if (fehler)
      return POLYSTAT_INVALID;

    int returnBuff=0x0;
//wenn sich die kanten schneiden wird der returnbuffer auf POLYSTAT_SCHNEIDET gesetzt
//(durch logisches oder können weitere statusmeldungen in returnBuff gespeichert werden)
    if (getKantenSchnitt())
      returnBuff=POLYSTAT_SCHNEIDET;

//die relative position des 3ten punktes zur kante zwischen 1stem und 2tem punkt wird
//festgestellt. die weiteren kanten müssen zu ihren nachfolgenden punkten denselben status
//aufweisen um konvex zu sein (sonst konkav)
    int linieAbsStat= kantenArray[0].getRelPos(getPunkt(2));

    for (int i=0;i<=kantenArray.length-1;i++)
    {
      int linieAktStat= kantenArray[i].getRelPos(getPunkt(i+2));
      if (linieAktStat==TLinie.RELPOS_DARAUF)
        returnBuff= POLYSTAT_INVALID|returnBuff;
      if (linieAktStat!=linieAbsStat)
        returnBuff= POLYSTAT_KONKAV|returnBuff;
    }
    return returnBuff;
  }
//prüft ob sich 2 kanten des Polygons schneiden
  public boolean getKantenSchnitt()
  {
    for (int i=0; i<=kantenArray.length-2; i++)
      for (int j=i+1;j<=kantenArray.length-1; j++)
      {
        if (kantenArray[i].getObSchnitt(kantenArray[j]))
          return true;
      }
    return false;
  }

//Interfaceimplementierung

  public String toString()
  {
    String strBuff=new String("Polygon: [");
    for (int i=0;i<=punkteArray.getObjZahl();i++)
      strBuff+=punkteArray.getTKoo2d(i).toString()+"; ";
    strBuff+="]\n";
    for (int i=0;i<=punkteArray.getObjZahl();i++)
      strBuff+=kantenArray[i].toString()+";\n";
    return strBuff;
  }
  public boolean setData (TVerglZuwObj obj)
  {
    return setData (obj, true);
  }
  public boolean setData (String[] str)
  {
    TKoo2d[] arrayBuff=new TKoo2d[str.length];
    for (int i=0;i<=str.length-1;i++)
    {
      arrayBuff[i]=new TKoo2d(str[i]);
      if (arrayBuff[i].getFehler())
        return false;
    }

    return setData(arrayBuff, false);
  }

  public boolean vergleich (TVerglZuwObj obj)
  {
    try
    {
      TPolygon o=(TPolygon)obj;
      if (o.punkteArray.getObjZahl()!=punkteArray.getObjZahl())
        return false;

      for (int i=0;i<=punkteArray.getObjZahl();i++)
        if (!o.getPunkt(i).vergleich(getPunkt(i)))
          return false;
    }
    catch (ClassCastException e)
    {
      return false;
    }
    return true;
  }
  public boolean getFehler()
  {
    return fehler;
  }

//setter Methoden
//diese methode erzeugt ein neues arrayobjekt für das kantenArray und erzeugt die
//linien neu (muss nur aufgerufen werden wenn neue punkte dem polygon hinzugefügt werden;
// falls die daten der punkte des polygons verändert werden ist dies nicht nötig, da die Linien
//die referenzen der polygonpunkte enthalten und somit mitverändert werden)
  public void kantenUpdate()
  {
    kantenArray= new TLinie[punkteArray.getObjZahl()+1];

    TLinie.setStdStartP(punkteArray.getTKoo2d(0),false);
    for (int i=0;i<=punkteArray.getObjZahl();i++)
    {
      kantenArray[i]=new TLinie(getPunkt(i+1,false),false);
    }
  }
//die folgenden methoden sind wie in den anderen Klassen settermethoden die
//entweder neue instanzen der daten erzeugen oder die referenzen zuweisen.
  public boolean setData(TVerglZuwObj obj, boolean punktKopie)
  {
    try
    {
      TPolygon o=(TPolygon)obj;

      return setData(o.getPunkte(false), punktKopie);
    }
    catch (ClassCastException e)
    {
      return false;
    }
  }
  public boolean setData (TKoo2d[] punkte, boolean punktKopie)
  {
    clearPunkte();
    addPunkte (punkte, punktKopie);
    if (punkte.length>=3)
      return true;
    else
      return false;
  }
  public boolean setData (TKoo2d[] punkte)
  {
    return setData (punkte, true);
  }
//diese methode löscht die daten des Polygons
  public void clearPunkte()
  {
    punkteArray= new TArrayAppendObj(new TKoo2d [10]);
    kantenArray=new TLinie[0];
    //kantenUpdate();
  }
//addPunkte fügt punkte.length  punkte dem Polygon hinzu
  public void addPunkte (TKoo2d[] punkte)
  {
    addPunkte (punkte, true);
  }

  public void addPunkte (TKoo2d[] punkte, boolean punktKopie)
  {

    if (punkteArray!=null)
    {
      punkteArray=new TArrayAppendObj(new TKoo2d[10]);
    }

    for (int i=0;i<=punkte.length-1;i++)
      if (punktKopie)
        punkteArray.appendObject(new TKoo2d(punkte[i]));
      else
        punkteArray.appendObject(punkte[i]);

    kantenUpdate();
  }
  public void addPunkt (TKoo2d punkt, boolean punktKopie)
  {
    TKoo2d[] arrayBuff=new TKoo2d[1];
    arrayBuff[0]=punkt;
    addPunkte (arrayBuff, punktKopie);
  }
  public void addPunkt (TKoo2d punkt)
  {
    addPunkt(punkt, true);
  }

//gettermethoden

  public TKoo2d[] getPunkte(boolean punktKopie)
  {
    if (punktKopie)
    {
//wenn punktKopie wird ein array mit neuen instanzen der polygonpunkte returned
      TKoo2d[] arrayBuff=new TKoo2d[punkteArray.getObjZahl()+1];
      for (int i=0;i<=punkteArray.getObjZahl();i++)
        arrayBuff[i]=new TKoo2d(punkteArray.getTKoo2d(i));
      return arrayBuff;
    }
    else
//ansonsten wird ein array mit den referenzen zu den polynompunkten returned
      return punkteArray.toTrimmedTKoo2dArray();
  }
  public TKoo2d[] getPunkte()
  {
    return getPunkte(true);
  }
//getPunkt gibt einen punkt des polygons zurück, wobei index beliebig groß sein kann
//(wenn größer als punktzahl ist wird von 0 zu zählen begonnen... sprich index wird modulo
//der zahl der Punkte des Polygons genommen)
  public TKoo2d getPunkt(int index, boolean punktKopie)
  {
    index=index%(punkteArray.getObjZahl()+1); // % damit man zb auf den punkt 0 auch mit index punkteArra.getObjZahl()+1 zugreifen kann
    return getPunkte(punktKopie)[index];
  }
//gibt die punktzahl des Polygons-1 zurück
  public int getPunktZahl ()
  {
    return punkteArray.getObjZahl();
  }
  public TKoo2d getPunkt (int index)
  {
    return getPunkt(index, true);
  }
//Konstruktoren
//wie bei den übrigen klassen rufen die Konstruktoren die setter Methoden auf
//und speichern in fehler ob diese erfolgreich waren
  public TPolygon (TKoo2d[] punkte, boolean punktKopie)
  {

    fehler=!setData (punkte, punktKopie);
  }
  public TPolygon (TKoo2d[] punkte)
  {
    this(punkte, true);
  }
  public TPolygon (String[] str)
  {

    fehler=!setData(str);
  }

  public TPolygon (TVerglZuwObj obj, boolean punktKopie)
  {

    fehler=!setData(obj, punktKopie);
  }
  public TPolygon (TVerglZuwObj obj)
  {
    this(obj, true);
  }
}