/*
 * ActivityResources.java
 *
 * Created on 12. říjen 2000, 13:09
 * Documented 7.7.2001
 */

package timetable.data;

import java.util.Vector;
/** Reprezentace množiny skupin zdrojů. Třída umožňuje i ukládání jednotlivých zdrojů - což je ekvivalentní skupinám zdrojů o jednom prvku.
 * <BR> Jde tedy o jakési pole proměnné délky, kde prvkem může být budto samotný zdroj nebo skupina zdrojů.
 *
 * @author Tomáš Müller
 * @version 1.0
 */
public class ActivityResources extends java.lang.Object implements java.io.Serializable{
    /** reprezentace skupin zdrojů třídou java.util.Vector */
    private Vector resources = new Vector();

    /** Konstruktor. */
    public ActivityResources() {
    }
    
    /** Konstruktor.
     * @param resource zdroj, který bude do množiny přidán.
     */
    public void add(Resource resource) {
        resources.add(resource);
    }

    /** Konstruktor.
     * @param resources skupina zdrojů, která bude do množiny přidána.
     */
    public void add(ResourceGroup resources) {
        this.resources.add(resources);
    }
    
    /** Nastaví zdroj či skupinu zdrojů na daném místě.
     * @param pos index pozice
     * @param o zdroj nebo skupina zdrojů, která bude uložena na dané pozici
     */
    public void setAt(int pos,Object o) {
        this.resources.setElementAt(o,pos);
    }
    
    /** Odstranění zdroje či skupiny zdrojů.
     * @param i index zdroje či skupiny zdrojů, který(á) má být odstraněn(a)
     */
    public void remove(int i) {
        resources.remove(i);
    }

    /** Odstranění zdroje či skupiny zdrojů
     * @param o zdoj či skupina zdrojů, který(á) má být odstraněn(a)
     */
    public void remove(Object o) {
        resources.remove(o);
    }
    
    /** Odstranění všech prvků množiny.*/
    public void removeAll() {
        resources.removeAllElements();
    }
    
    /** Vrátí počet prvků v množině. Tedy počet zdrojů či skupin zdrojů ve skupině.
     * @return počet prvků
     */
    public int size() {
        return resources.size();
    }
    
    /** Zjistí, zda-li je i-tý prvek skupina nebo samostatný zdroj
     * @return true, pokud jde o skupinu
     */
    public boolean isGroup(int i) {
        return (resources.get(i) instanceof ResourceGroup);
    }
    
    /** Zjistí umístění zdroje či skupiny zdrojů v množině
     * @param o hledaný zdroj či skupina zdrojů
     * @return příslušný index, -1 pokud takový prvek ve množině není
     */
    public int indexOf(Object o) {
        return resources.indexOf(o);
    }
    
    /** Vrátí index prvku (zdroje či skupiny zdrojů) který obsahuje daný zdroj.
     * @param resource hledaný zdroj
     * @return index zdroje či skupiny zdrojů, který je (nebo která obsahuje) příslušný zdroj
     */
    public int contains(Resource resource) {
        for (int i=0;i<size();i++)
            if (isGroup(i)) {
                if (getResources(i).indexOf(resource)>=0) return i;
            } else {
                if (getResource(i)==resource) return i;
            };
        return -1;
    }
    
    /** Vrátí zdroj na dané pozici. 
     * @param i index ve množině
     * @return příslušný zdroj (Pokud je na dané pozici skupina zdrojů, návratová hodnota bude null)
     */
    public Resource getResource(int i) {
        try {
            return (Resource) (resources.get(i));
        } catch (Exception e) {
            return null;
        }
    }

    /** Vrátí skupinu zdrojů na dané pozici
     * @param i index ve množině
     * @return příslušná skupina zdrojů (Pokud je na dané pozici samostaný zdroj, návratová hodnota bude null)
     */
    public ResourceGroup getResources(int i) {
        try {
            return (ResourceGroup) (resources.get(i));
        } catch (Exception e) {
            return null;
        }
    }
    
    /** Zjistí, zda-li může být daná množina požadovaných zdrojů použita pro plánování v daný čas. To znamená, že musejí být použitelné všechny zdroje v množině, pokud jde o skupinu záleží navíc na tom, zda-li je konjunktivní. Pokud je skupina konjunktivní, musejí být použitelné všechny zdroje, pokud je disjunktivní, musí jít použít alespoň jeden zdroj.
     * <BR>Použitelnost znamená, že daná zdroj může být uvolněn pro plánování a žádná HARD podmínka nebude porušena.
     * @param slot první slot časového úseku
     * @length počet slotů časového úseku (sloty <code>slot .. slot+length-1</code> jsou kontrolovány)
     * @return true, pokud ano (aktivita lze tedy naplánovat na dané místo)
     */
    public boolean canAllBeFreeAt(int slot, int length) {
        for (int i=0;i<size();i++) {
            if (isGroup(i)) {
                if (getResources(i).conjunctive) {
                    if (!getResources(i).canAllBeFreeAt(slot,length)) return false;
                } else {
                    if (!getResources(i).canOneBeFreeAt(slot,length)) return false;
                }
            } else {
                if (!getResource(i).canBeFreeAt(slot,length)) return false;
            }
        }
        return true;
    }

    /** Zjistí, zda-li je daná množina požadovaných zdrojů volná v daný čas. (v případě disjunktivních skupin stačí aby byl volný pouze jeden zdroj skupiny)
     * @param slot první slot časového úseku
     * @length počet slotů časového úseku (sloty <code>slot .. slot+length-1</code> jsou kontrolovány)
     * @return true, pokud ano (aktivita lze tedy naplánovat na dané místo bez konfliktu)
     */
    public boolean isAllFreeAt(int slot, int length) {
        for (int i=0;i<size();i++) {
            if (isGroup(i)) {
                if (getResources(i).conjunctive) {
                    if (!getResources(i).isAllFreeAt(slot,length)) return false;
                } else {
                    if (!getResources(i).isOneFreeAt(slot,length)) return false;
                }
            } else {
                if (!getResource(i).isFreeAt(slot,length)) return false;
            }
        }
        return true;
    }

    /** Spočte počet možných umístění aktivity v daný čas bez konfliktu. 
     * @param slot první slot časového úseku
     * @length počet slotů časového úseku (sloty <code>slot .. slot+length-1</code> jsou kontrolovány)
     * @return 0, pokud aktivita nemůže být naplánována. Jinak jde o součin volných zdrojů disjunktních skupin v daný čas)
     */
    public int countAllFreeAt(int slot, int length) {
        int sum =1;
        for (int i=0;i<size();i++) {
            if (isGroup(i)) {
                if (getResources(i).conjunctive) {
                    if (!getResources(i).isAllFreeAt(slot,length)) return 0;
                } else {
                    sum*=getResources(i).countFreeAt(slot,length);
                    if (sum==0) return 0;
                }
            } else {
                if (!getResource(i).isFreeAt(slot,length)) return 0;
            }
        }
        return sum;
    }

    /** Zápis množiny na stream 
     * @param out stream
     */
   private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
       out.writeObject(resources);
   }

    /** Načtení množiny ze streamu
     * @param in stream
     */
   private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
       resources = (Vector) in.readObject();
   }
   
    /** Zápis množiny na stream 
     * @param out stream
     * @param allResources množina všech zdrojů
     */
   public void write(java.io.ObjectOutputStream out, ResourceGroup allResources) throws java.io.IOException {
       out.writeInt(size());
       for (int i=0;i<size();i++) {
           out.writeBoolean(isGroup(i));
           if (isGroup(i)) {
               getResources(i).write(out, allResources);
           } else {
               getResource(i).write(out, allResources);
           };
       };
   }
   
    /** Načtení množiny ze streamu 
     * @param in stream
     * @param allResources množina všech zdrojů
     * @return načtená množina 
     */
   public static ActivityResources read(java.io.ObjectInputStream in, ResourceGroup allResources)  throws java.io.IOException, java.lang.ClassNotFoundException {
       int size = in.readInt();
       ActivityResources ar = new ActivityResources();
       for (int i=0;i<size;i++) {
           if (in.readBoolean()) {
               ar.add(ResourceGroup.read(in,allResources));
           } else {
               ar.add(Resource.read(in,allResources));
           };
       };
       return ar;
   }
   
   /** Vytvoří jinou instanci této množiny
    * @return jiná instance stejné množiny
    */
    public Object clone() {
        ActivityResources g = new ActivityResources();
        for (int i=0;i<size();i++) 
            if (isGroup(i))
                g.add(getResources(i));
            else 
                g.add(getResource(i));
        return g;
    }       
    
    /* Vrátí řetězec zkratek jmen jednotlivých zdrojů. Příklad: "Z1, {Z2}, {Z3, Z4}" (Z1 je samostatný zdroj, ostatní jsou skupiny)
     * @return řetězec představující zkratky jmen jednotlivých zdrojů
     */
    public String toString() {
        StringBuffer sb = new StringBuffer();
        for (int i=0;i<size();i++) {
            if (i!=0) sb.append(", ");
            if (isGroup(i))
              sb.append(getResources(i).toString());
            else
              sb.append(getResource(i).toString());
        };
        return sb.toString();
    }

}
