/**
 *  File neve : Rajzpanel.java (Rajzpanel osztály)
 *
 *  Leírás : Ez az osztály amin a grafikus műveletek történnek
 *           a 'graf' típusú 'epulet' egyed segítségével.
 *           Az 'epulet' egyed segítségével teszi a gráfot vizuálisan is
 *           láthatóvá. Mindennemü változás (csúcsok mozgatása, új csúcs
 *           felvétele stb) azonnal megjelenik a gráfban.
 *           A konstruktor parametérei : 'parent' : a szülő ScrollPane,
 *           'filenev' : a file-nak a neve amelyből a gráfot töltjük be.
 *
 *  Készítette Takács Mihály 1998.06. 
 */

import java.util.*;
import java.awt.event.*;
import java.awt.*;

class Rajzpanel extends Panel implements MouseListener, ActionListener,
				    MouseMotionListener {
  ScrollPane parent;  // A befoglaló ScrollPane
  PopupMenu PopupUj,PopupRegi;  // Új terminálhoz és már meglévő terminálhoz
  MenuItem ujterminal, // Új terminálhoz és
           tulajdonsag,torles;  // már meglévó terminálhoz
  graf epulet;    // Maga a gráf amit vizuálisan is megjelenítÜnk
  lista csucsok;  // A gráf összes csúcsa egy vektorban
  boolean valtozas=false; // Ha történt változtatás akkor igaz (mentéshez)

  Rajzpanel(ScrollPane parent,String filenev) {
    if (filenev.equals("")) { // Új gráf gyökerének a létrehozása
      TermDialog ujterm=new TermDialog((Frame)parent.getParent(),this,"Új",new Point(100,100),"","","","","","");  // A második szülő a Frame (FoMenu)
      ujterm.show();
    } else if (!beolvas(filenev)) {   // Ha rossz a beolvasás akkor új gráf
      setEnabled(false);
      setSize(5,5);
      ((FoMenu)parent.getParent()).csoportok.setEnabled(false);
      ((FoMenu)parent.getParent()).ment.setEnabled(false);
      ((FoMenu)parent.getParent()).bezar.setEnabled(false);
      Uzenet uzen=new Uzenet((Frame)parent.getParent(),"Hiba","HIBA : Nem letezo file vagy rossz file formatum!",Uzenet.hiba);  // Üzenő ablak
      epulet=new graf("semmi");
    }

    if (isEnabled()) setSize(2000,1000);
    this.parent=parent;
    PopupUj=new PopupMenu();  /* A PopupMenu-k */
      ujterminal=new MenuItem("Uj terminal");
      ujterminal.addActionListener(this);
      PopupUj.add(ujterminal);
    PopupRegi=new PopupMenu();
      tulajdonsag=new MenuItem("Tulajdonsag");
      tulajdonsag.addActionListener(this);
      PopupRegi.add(tulajdonsag);
      torles=new MenuItem("Torles");
      torles.addActionListener(this);
      PopupRegi.add(torles);
    add(PopupUj);
    add(PopupRegi);
    addMouseListener(this);
    addMouseMotionListener(this);
  }

  Image offscreen;  // Pufferelt rajzoláshoz
  Dimension offscreensize;
  Graphics offgraphics;
  
  final Color selectColor = Color.pink;
  final Color lineColor = Color.black;
  final Color csucsColor = new Color(250, 220, 100);

  public void paintcsucs(Graphics g, csucs n, FontMetrics fm) {
    int x = n.x;
    int y = n.y;
    g.setColor(n.select ? selectColor : csucsColor);
    int w = fm.stringWidth(n.neve)+10;
    int h = fm.getHeight()+4;
    n.dx = w;
    n.dy = h;
    g.fillRect(x,y,w,h);
    g.setColor(Color.black);
    g.drawRect(x,y,w-1,h-1);
    g.drawString(n.neve,x+5,y+2+fm.getAscent());
  }

  public void update(Graphics g) {
    setSize(2000,1000);
    Dimension d=size();
    csucs aktualis,rakovetkezo;

    if ((offscreen==null) || /* Ha még nem volt vagy át volt méretezve */
	(d.width!=offscreensize.width) || (d.height!=offscreensize.height)) {
      offscreen = createImage(d.width, d.height);
      offscreensize = d;
      offgraphics = offscreen.getGraphics();
      offgraphics.setFont(getFont());
    }
    offgraphics.setColor(getBackground());  // Offscreen törlése
    offgraphics.fillRect(0, 0, d.width, d.height);
    /*
     * Sorra vesszük a csúcskat és a rákövetkező csúcsaival összekötjük
     * őt. Vagyis a csúcskat összekötő szakaszok kirajzolása. 
     */
    csucsok=epulet.csucsok();
    for (Enumeration e=csucsok.elements(); e.hasMoreElements(); ) {
      aktualis=(csucs)e.nextElement();
      if (!aktualis.torolt && (aktualis.x!=csucs.valotlan)) {
	for (Enumeration f=aktualis.kovetkezo.elements();
	     f.hasMoreElements(); ) { // A rákövetkező csúcsok sorban
	  rakovetkezo=(csucs)f.nextElement();
	  if (!rakovetkezo.torolt && (rakovetkezo.x!=csucs.valotlan)) {
	             /* A szakasz kirajzolása */
	    /* A csúcsok közepének koordinátái */
	    int kozepx1 = aktualis.x+aktualis.dx/2;
	    int kozepy1 = aktualis.y+aktualis.dy/2;
	    int kozepx2 = rakovetkezo.x+rakovetkezo.dx/2;
	    int kozepy2 = rakovetkezo.y+rakovetkezo.dy/2;
	    offgraphics.setColor(lineColor); // A szakasz megrajzolása
	    offgraphics.drawLine(kozepx1,kozepy1,kozepx2,kozepy2);
	    /* A nyíl kirajzolása a szakaszra. */
	    int Xtav=kozepx2-kozepx1; // A szakasz vektor x koordinátája
	    int Ytav=kozepy2-kozepy1; // A szakasz vektor y koordinátája
	    double len=Math.abs(Math.sqrt(Xtav*Xtav+Ytav*Ytav));//szakaszhossz
	    if (len>10) {  // Csak ekkor rajzolunk nyílat
	      double arany=5/len;  // A nyíl hossza mindig 5 egység
	      int vx=(int)(Xtav*arany); //Ez a nyíl helyét mutatja
	      int vy=(int)(Ytav*arany);
	      // Oda nyíl
	      int szakaszkozepex=(kozepx2+kozepx1)/2; //A szakasz felező
	      int szakaszkozepey=(kozepy2+kozepy1)/2; //    pontja
	      offgraphics.drawLine(szakaszkozepex+vx*2, szakaszkozepey+vy*2,
				   szakaszkozepex+vy  , szakaszkozepey-vx);
	      offgraphics.drawLine(szakaszkozepex+vx*2, szakaszkozepey+vy*2,
				   szakaszkozepex-vy  , szakaszkozepey+vx);
	    }
	  }
	}
      }
    }
    /* A csúcsok kirajzolása */
    FontMetrics fm = offgraphics.getFontMetrics();
    for (Enumeration e=csucsok.elements(); e.hasMoreElements(); ) {
      aktualis=(csucs)e.nextElement();
      if (!aktualis.torolt && (aktualis.x!=csucs.valotlan)) {
	paintcsucs(offgraphics, aktualis, fm);
      }
    }
    g.drawImage(offscreen, 0, 0, null);  // Képernyőváltás
  }
  
     /* MouseMotionListener interfész implementalásá */

  int tavX,tavY;  /* A csúcs balfelső sarkától ennyire klikkeltünk */
  csucs pick;  // Melyik csúcs felett klikkeltünk (pl. mozgatás)
  int duplaklikk=0;  // A duplakattintás számolásához a mouseClicked fv-ben
  public void mouseMoved(MouseEvent evt) {duplaklikk=0;}

  public void mouseDragged(MouseEvent evt) {
    try {
      int x=evt.getX();
      int y=evt.getY();
      Dimension d=getSize();
      if (x<tavX) pick.x=0;  // Bal szélén akarja kimozgatni
      else if (d.width<(x-tavX+pick.dx)) pick.x=d.width-pick.dx;// Jobbszéle
      else pick.x = x-tavX;  // Közepe
      if (y<tavY) pick.y=0;  // Teteje
      else if (d.height<(y-tavY+pick.dy)) pick.y=d.height-pick.dy; // Alja
      else pick.y = y-tavY;  // Közepe
      valtozas=true;
    } catch (Exception err) {} // NullPointer hiba lehet, pick=null
    repaint();
  }

     /* MouseListener interfész implementálása */
  Point TermPosition=new Point(0,0);  // A terminal pozíciója (esemény helye)
  csucs popupselect;  // Melyik csúcs fölött nyomtunk popup menüt

  public void mouseClicked(MouseEvent evt) {
    if ((++duplaklikk)%2==0) {
      duplaklikk=0;
      TermPosition=evt.getPoint();
      if ((popupselect=epulet.Keres(TermPosition.x,TermPosition.y))!=null) {
	tavX=TermPosition.x-popupselect.x;
	tavY=TermPosition.y-popupselect.y;
	actionPerformed(new ActionEvent(tulajdonsag,ActionEvent.ACTION_PERFORMED,"Tulajdonsag",0));
      } else {  // Nem csúcs felett klikkelt duplán
	actionPerformed(new ActionEvent(ujterminal,ActionEvent.ACTION_PERFORMED,"UjTerminal",0));
      }
    }
  }

  public void mousePressed(MouseEvent evt) {
    if (evt.isPopupTrigger()) {  // Ha PopupMenu-t aktivizáltunk
      TermPosition=evt.getPoint();
      if ((popupselect=epulet.Keres(TermPosition.x,TermPosition.y))!=null) {
	// Ha csúcson klikkeltünk
	tavX=TermPosition.x-popupselect.x;
	tavY=TermPosition.y-popupselect.y;
	PopupRegi.show(this,TermPosition.x,TermPosition.y); //PopupMenu
      } else {  // Ha nem csúcson klikkeltünk
	PopupUj.show(this,TermPosition.x,TermPosition.y);
      }
    } else {  // Lehet hogy csúcsot fogunk mozgatni
      int x=evt.getX();
      int y=evt.getY();
      if ((pick=epulet.Keres(x,y))!=null) {  // Ha csúcson klikkeltünk
	tavX=x-pick.x;
	tavY=y-pick.y;
      	pick.select=true;  // Szürke színnel rajzoljuk ki
      }
    }
    repaint();
  }

  public void mouseReleased(MouseEvent evt) {
    try {
      pick.select=false;  // Már nem kell szürkén kirajzolni
      pick = null;
      tavX=0;
      tavY=0;
    }
    catch (Exception err) {} // NullPointer hiba lehet, pick=null
    repaint();
  }

  public void mouseEntered(MouseEvent evt) {repaint();}
  public void mouseExited(MouseEvent evt) {}

	/* ActionListener interfész implementálása a PopupMenu-khöz */
  public void actionPerformed(ActionEvent evt) {
    Object s=evt.getSource();  // Visszaadja honnan jött az esemény
    /* A popup menü menüpontjai */
    if       (s.equals(ujterminal  )) {
      TermDialog ujterm=new TermDialog((Frame)parent.getParent(),this,"Új Terminál",TermPosition,"","","","","","");  // A második szülő a Frame (FoMenu)
      ujterm.show();
    }else if (s.equals(tulajdonsag )) {
      TermDialog regiterm=new TermDialog((Frame)parent.getParent(),
	 this,"Terminál tulajdonságai",TermPosition,popupselect.neve,
	 popupselect.azonosito,popupselect.kovetkezok(),popupselect.csoport,
	 popupselect.tol,popupselect.ig);
                   // A második szülő a Frame (FoMenu)
      regiterm.show();
    }else if (s.equals(torles      )) {
      if (popupselect==epulet.getGyoker()) {
	Uzenet uzen=new Uzenet((Frame)parent.getParent(),"Hiba",
	   "HIBA : A gyokerelem nem torolheto!",Uzenet.hiba);  // Üzenő ablak
      } else {
	epulet.torol(popupselect);
	popupselect=null;
	valtozas=true;
      }
    }
    repaint();
  }

   /** 
    * TermDialog példány ad hozzá új csúcsot vagy módosít ezen keresztül
    **/
  public void hozzaad(String neve, String azonosito, String csoport,
		 String kovetkezok, int x, int y, String tol, String ig) {
    try {
      epulet.ujelem(neve,azonosito,csoport,kovetkezok,x-tavX,y-tavY,1,tol,ig);
    } catch (NullPointerException err) {
      /* Most hozzuk létre az épületet, ez lesz a gráf gyökere */
      epulet=new graf(azonosito);
      epulet.ujelem(neve,azonosito,csoport,kovetkezok,x,y,1,tol,ig);
    }
    csucsok=epulet.csucsok();
    valtozas=true;
    tavX=0; tavY=0;
  }
    /** 
      * Ezen keresztül tud menteni a FoMenu egyed (a szülő)
      **/
  public void ment(String filenev) {
    epulet.ment(filenev);
    valtozas=false;   // Már nincs változás
  }

    /** 
     * Ezen keresztül tud beolvasni a FoMenu egyed (a szülő)
     **/
  public boolean beolvas(String filenev) {
    boolean l;
    epulet=new graf();
    l=epulet.beolvas(filenev);
    if (l) csucsok=epulet.csucsok();  // Csak ha sikeres a beolvasás
    valtozas=false;  // Ebben még nincs változás
    return l;
  }
    /**
     * Ezen keresztül törölhet a TermDialog ablak csúcsot
     **/
  public void torol(String azonosito) {
    csucs a;
    if ((a=epulet.Keres(azonosito))==epulet.getGyoker()) {
      Uzenet uzen=new Uzenet((Frame)parent.getParent(),"Hiba","HIBA : A gyoker elem nem torolheto!",Uzenet.hiba);  // Üzenő ablak
    } else {
      try {
	epulet.torol(a);  // Az 'a' csúcs null pointer is lehet
      } catch (NullPointerException err) {}
    }
  }
}
