
// WorldItems.java 
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Třída WorldItems udžuje seznam objektů typu TileOccupier uspořádaných dle řádku dalždice.
   Když se objekty vykreslují, je vynuceno správné z-ové uspořádání, aby se objekty
   vpředu vykreslili před objekty vzadu.

   Instance třídy TileOccupier může reprezentovat BLOCK, PICKUP či SPRITE.

   Předmět je po sebrání hráčem z objektu typu WorldItems vymazán.

   Sprity se při vykreslování přidávají jen dočasně, protože se při pohybu
   herním světem mění jejich z-ová pozice v seznamu.
*/

import java.awt.*;
import java.util.*;
import java.awt.image.*;


public class WorldItems
{
  // maximální šířka/výška dlaždice v pixelech (včetně mezery k další dalždici)
  private int tileWidth, tileHeight;

  // souřadnice začátku prvního sudého řádku
  /* Souřadnicí je levý horní roh obdélníka obsahujícího tvar kosočtverce */
  private int evenRowX, evenRowY;

  // souřadnice začátku prvního lichého řádku
  private int oddRowX, oddRowY;

  private ArrayList items;    
         // seznam objektů typu TileOccupier setříděný dle řádku



  public WorldItems(int w, int h, int erX, int erY,
                                  int orX, int orY)
  { tileWidth = w; tileHeight = h;
    evenRowX = erX; evenRowY = erY;
    oddRowX = orX; oddRowY = orY;
    items = new ArrayList();
  }  // konec konstruktoru: WorldItems()



  public void addItem(String name, int type, int x, int y, BufferedImage im)
  /* Při vytváření objektu typu TileOccupier mu musíme předat relevantní 
     souřadnice řádku v závislosti na tom, je-li v sudém či lichém řádku. Dále
     jsou potřeba rozměry dlaždice v pixelech, aby se předměty mohly vykreslit 
     v panelu JPanel na správném místě. 
     
     Souřadnice dlaždice pro daný předmět jsou v paremtrech (x,y). Parametr
     type může být buď BLOCK nebo PICKUP. Entity typu SPRITE řeší metoda positionSprite()
     uvedená níže.
  */
  {
    TileOccupier toc;
    if (y%2 == 0) // sudý řádek
      toc = new TileOccupier(name, type, x, y, im, 
                                    evenRowX, evenRowY,
                                    tileWidth, tileHeight);
    else
      toc = new TileOccupier(name, type, x, y, im, 
                                    oddRowX, oddRowY,
                                    tileWidth, tileHeight);
    rowInsert(toc, x, y);
  } // konec metody: addItem()


  private void rowInsert(TileOccupier toc, int x, int y)
  /* Vloží předmět okupanta do seznamu. V rámci jednoho řádku
     jsou předměty seřazeny podle jejich pozice ve sloupci. */
  {
    TileOccupier item;
    Point itemPt;
    int i = 0;
    while(i < items.size()) {
      item = (TileOccupier) items.get(i);
      itemPt = item.getTileLoc();
      if (y < itemPt.y)   
        break;
      else if ((y == itemPt.y) && (x < itemPt.x))
        break;
      i++;
    }
    items.add(i, toc);
  } // konec metody: rowInsert()



  public void draw(Graphics g, int xOffset, int yOffset)
  /* Vykreslí všechny předměty. Protože předměty jsou setříděny
     dle řádků, vykreslí se na obrazovku ve správném z-ovém
     uspořádáním odzadu dopředu. */
  {
    TileOccupier item;
    for(int i = 0; i < items.size(); i++) {
      item = (TileOccupier) items.get(i);
      item.draw(g, xOffset, yOffset);    // vykresli předmět
    }
  }  // konec metody: draw()



  // ------------------------ metody vztahující se ke spritům -----------------


  public void positionSprites(PlayerSprite ps, AlienSprite[] aliens)
  // Přidá hráče a vetřelce k předmětům herního světa
  {
    posnSprite("bob", ps);    // vytvoř unikátní jméno
    for(int i = 0; i < aliens.length; i++)
      posnSprite("alien "+i, aliens[i]);
  }  // konec metody: positionSprites()


  private void posnSprite(String name, TiledSprite tSprite)
  /* Přidá objekt typu TiledSprite s názvem name seznamu.
     Tato metoda je variantou metody addItem(). */
  {
    Point sPt = tSprite.getTileLoc();

    TileOccupier toc;
    if (sPt.y%2 == 0) // sudý řádek
      toc = new TileOccupier(name, WorldDisplay.SPRITE, 
                                    sPt.x, sPt.y, tSprite.getImage(),
                                    evenRowX, evenRowY,
                                    tileWidth, tileHeight);
    else
      toc = new TileOccupier(name, WorldDisplay.SPRITE, 
                                    sPt.x, sPt.y, tSprite.getImage(), 
                                    oddRowX, oddRowY,
                                    tileWidth, tileHeight);

    toc.addSpriteRef(tSprite); 
       /* odkaz na sprite se použije při vykreslování předmětu,
	  aby se zajistilo, že se vykreslí správný obrázek spritu. */
    rowInsert(toc, sPt.x, sPt.y);
  } // konec metody: posnSprite()



  public void removeSprites()
  // odebere všechny sprity v seznamu, na základě typu
  {
    TileOccupier item;
    int i = 0;
    while(i < items.size()) {
      item = (TileOccupier) items.get(i);
      if (item.getType() == WorldDisplay.SPRITE)
        items.remove(i);
      else
        i++;
    }
  } // konec metody: removeSprites()



  // -------------------------- metody vztahující se k sebratelným předmětům ------------------


  public String findmickupName(Point pt)
  /* Nachází-li se bod pt na stejné pozici jako předmět,
     pak vrátí název předmětu, jinak null. */
  {
    TileOccupier item;
    for(int i=0; i < items.size(); i++) {
      item = (TileOccupier) items.get(i);
      if ((item.getType() == WorldDisplay.PICKUP) && 
          (pt.equals( item.getTileLoc())))    // najdi předmět na pozici pt
        return item.getName();
    }
    return null;
  }  // konec metody: findmickupName()



  public Point nearestPickup(Point pt)
  /* Vrátí předmět nejblíže bodu pt.
     Srovná bod pt se čtvercem jeho vzdálenosti ke každému předmětu.
     Pomocí čtverce vzdálenosti se vyhneme problémům s negativními vzdálenostmi.
  */
  {
    double minDist = 1000000;   // uměle velká hodnota
    Point minPoint = null;
    double dist;
    TileOccupier item;
    for(int i=0; i < items.size(); i++) {
      item = (TileOccupier) items.get(i);
      if (item.getType() == WorldDisplay.PICKUP) { 
        dist = pt.distanceSq( item.getTileLoc() );  // zjisti čtverec vzdálenosti k předmětu
        if (dist < minDist) {
          minDist = dist;                // ulož nejmenší vzdálenost
          minPoint = item.getTileLoc();  // ulož asociovaný bod
        }
      }
    }
    return minPoint;
  }  // konec metody: nearestPickup()


  public boolean removePickup(String name)
  // Pokusí se smazat předmět s názvem name
  {
    TileOccupier item;
    for(int i=0; i < items.size(); i++) {
      item = (TileOccupier) items.get(i);
      if ((item.getType() == WorldDisplay.PICKUP) && 
          (name.equals(item.getName()))) {    // najdi předmět daného jména
        items.remove(i);
        return true;
      }
    }
    return false;
  }  // konec metody: removePickup()


}  // konec třídy: WorldItems

