/*
 * ResourceGroup.java
 *
 * Created on 12. říjen 2000, 10:48
 * Documented 7.7.2001
 */

package timetable.data;

import java.util.Vector;
import timetable.util.*;
/** Reprezantace skupiny zdrojů v rozvrhovacím problému.
 *
 * @author Tomáš Müller
 * @version 1.0
 */
public class ResourceGroup extends java.lang.Object { 
    /** Reprezentace zdrojů pomocí třídy java.util.Vector */
    protected Vector resources = new Vector();
    
    /** Zkratka jména skupiny zdrojů*/
    public String shortCut=null;
    /** Poznámka*/
    public String note=null;
    /** Jméno*/
    public String name=null;
    /** Příznak změny*/
    public boolean changed=false;
    /** Příznak konjunktivní či disjunktivní skupiny zdrojů */
    public boolean conjunctive=false;
    
    /** Konstruktor. */
    public ResourceGroup() {
    }
    
    /** Konstruktor.
     * @param name jméno skupiny
     */
    public ResourceGroup(String name) {
        this.name=name;
    }
    
    /** Konstruktor.
     * @param resource Zdroj resource bude přidán do skupiny po jejím vytvoření.
     */
    public ResourceGroup(Resource resource) {
        resources.add(resource);
    }
    
    /** Konstruktor.
     * @param resource skupina zdrojů bude přidána do skupiny po jejím vytvoření.
     */
    public ResourceGroup(Resource[] resource) {
        for (int i=0; i<resource.length;i++)
            resources.add(resource[i]);
    }
    
    /** Nastavení jména.
     * @param name jméno
     */
    public void setName(String name) {
        this.name=name;
        changed=true;
    }
    
    /** Získání jména skupiny
     * @return jméno skupiny
     */
    public String getName() { return name;}
    
    /** Přidání zdroje do skupiny
     * @param zdroj
     */
    public void add(Resource resource) {
        resources.add(resource);
        changed=true;
    }
    
    /** Odebrání zdroje ze skupiny
     * @param zdroj
     */
    public void remove(Resource resource) {
        resources.remove(resource);
        changed=true;
    }
    
    /** Dotaz na změnu skupiny
     * @return true, pokud byla změna
     */
    public boolean isChanged() { 
        return changed; 
    }
    
    /** Dotaz na přítomnost zdroje ve skupině
     * @param resource zdroj
     * @return true, pokud je zdroj ve skupině
     */
    public boolean isInGroup(Resource resource) {
        for (int i=0;i<size();i++) 
            if (get(i)==resource) return true;
        return false;
    }
    
    /** Odebrání všech zdrojů ze skupiny
     */
    public void removeAll() {
        resources.clear();
    }
    
    /** Vrátí počet zdrojů ve skupině
     * @return počet zdrojů ve skupině
     */
    public int size() {
        return resources.size();
    }
    
    /** Vrátí zdroj s požadovaným indexem. Tento index je číslován od 0.
     * @param i index zdroje ve skupině
     * @return zdroj s indexem i 
     */ 
    public Resource get(int i) {
        try {
            return (Resource) resources.get(i);
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            return null;
        }
    }
    
    /** Nastavení zdroje s indexem
     * @param i index zdroje ve skupině
     * @param resource zdroj, který bude na toto místu umístěn
     */
    public void set(int i,Resource resource) {
        resources.set(i,resource);
    }
    
    /** Vrátí index požadovaného zdroje.
     * @param resource zdroj
     * @return index zdroje ve skupině, -1 pokud tam není
     */
    public int indexOf(Resource resource) {
        return resources.indexOf(resource);
    }
    
    /** Otázka, zda-li je jeden ze zdrojů ve skupině v požadovaný čas volný.
     * @param slot požadovaný časový slot
     * @param length délka aktivity, pro kterou se daná operace zjišťuje -> jsou procházeny sloty <code>slot .. slot+lengt-1</code>
     * @return true, pokud takový zdroj ve skupině je
     */
    public boolean isOneFreeAt(int slot, int length) {
        for (int i=0;i<size();i++) 
            if (get(i).isFreeAt(slot,length)) return true;
        return false;
    }
    
    /** Otázka, zda-li jsou všechny zdroje ve skupině v požadovaný čas volné.
     * @param slot požadovaný časový slot
     * @param length délka aktivity, pro kterou se daná operace zjišťuje -> jsou procházeny sloty <code>slot .. slot+lengt-1</code>
     * @return true, pokud jsou volné
     */
    public boolean isAllFreeAt(int slot, int length) {
        for (int i=0;i<size();i++)
            if (!get(i).isFreeAt(slot,length)) return false;
        return true;
    }

    /** Otázka, zda-li může být jeden ze zdrojů ve skupině v požadovaný čas volný. To znamená, že dané sloty nemají HARD podmínku a případní aktivity v nich umístěné jdou odebrat.
     * @param slot požadovaný časový slot
     * @param length délka aktivity, pro kterou se daná operace zjišťuje -> jsou procházeny sloty <code>slot .. slot+lengt-1</code>
     * @return true, pokud takový zdroj ve skupině je
     */
    public boolean canOneBeFreeAt(int slot, int length) {
        for (int i=0;i<size();i++) 
            if (get(i).canBeFreeAt(slot,length)) return true;
        return false;
    }

    /** Otázka, zda-li může být všechny zdroje ve skupině v požadovaný čas volné. To znamená, že dané sloty nemají HARD podmínku a případní aktivity v nich umístěné jdou odebrat.
     * @param slot požadovaný časový slot
     * @param length délka aktivity, pro kterou se daná operace zjišťuje -> jsou procházeny sloty <code>slot .. slot+lengt-1</code>
     * @return true, pokud ano
     */
    public boolean canAllBeFreeAt(int slot, int length) {
        for (int i=0;i<size();i++) 
            if (!get(i).canBeFreeAt(slot,length)) return false;
        return true;
    }

    /** Spočte počet volných zdrojů v daný čas ve skupině.
     * @param slot požadovaný časový slot
     * @param length délka aktivity, pro kterou se daná operace zjišťuje -> jsou procházeny sloty <code>slot .. slot+lengt-1</code>
     * @return počet volných zdrojů
     */
    public int countFreeAt(int slot, int length) {
        int sum=0;
        for (int i=0;i<size();i++) 
            if (get(i).isFreeAt(slot,length)) sum++;
        return sum;
    }

    /** Vrátí skupinu volných zdrojů v daný čas
     * @param slot požadovaný časový slot
     * @param length délka aktivity, pro kterou se daná operace zjišťuje -> jsou procházeny sloty <code>slot .. slot+lengt-1</code>
     * @return skupina volných zdrojů
     */
    public ResourceGroup getFreeAt(int slot, int length) {
        ResourceGroup g = new ResourceGroup();
        boolean free=true;
        for (int i=0; i<this.size();i++) 
            if (get(i).isFreeAt(slot,length)) g.add(get(i));
        return g;
    }
    
    /** Vrátí jinou instanci této skupiny. 
     * @return jiná instance stejné skupiny
     */
    public Object clone() {
        ResourceGroup g = new ResourceGroup();
        g.setName(getName());
        g.note=this.note;
        g.shortCut=this.shortCut;
        g.conjunctive=this.conjunctive;
        for (int i=0;i<size();i++) 
            g.add(get(i));
        return g;
    }    
    
    /** Porovná na rovnost dvě skupiny
     * @param o druhá skupina
     * @return true, pokud obsahují stejné zdroje (ve stejném pořadí) a mají stejné parametry
     */
    public boolean equals(Object o) {
        if (o==null) return false;
        if (o instanceof ResourceGroup) {
            ResourceGroup g = (ResourceGroup) o;
            if (shortCut==null && shortCut!=g.shortCut) return false;
            if (shortCut!=null && !shortCut.equals(g.shortCut)) return false;
            if (name==null && name!=g.name) return false;
            if (name!=null && !name.equals(g.name)) return false;
            if (conjunctive!=g.conjunctive) return false;
            if (size()!=g.size()) return false;
            for (int i=0;i<size();i++) 
                if (g.get(i)!=get(i)) return false;
            return true;
        } else return false;
    }
    
    /** Zjistí, zda-li dvě skupiny obsahují stejné zdroje.
     * @param r druhá skupina
     * @return true, pokud obě skupiny obsahují stejné zdroje (i v jiném pořadí)
     */
    public boolean haveSameContent(ResourceGroup r) {
        if (r==null) return false;
        if (r.size()!=size()) return false;
        for (int i=0;i<size();i++)
            if (r.indexOf(get(i))<0) return false;
        return true;
    }
    
    /** Zápis skupiny do streamu.
     * @param out stream
     * @param allActivities množina všech aktivit
     */
    protected void write(java.io.ObjectOutputStream out, ActivityGroup allActivities) throws java.io.IOException {
       out.writeInt(size());
       for (int i=0;i<size();i++)
           get(i).write(out, allActivities);
   }

   /** Načtení skupiny ze streamu
    * @param in stream
    * @param config konfigurace
    * @return načtená skupina
    */
   protected static ResourceGroup read(java.io.ObjectInputStream in, Config config) throws java.io.IOException, java.lang.ClassNotFoundException, TimetableException {
       int nrResources=in.readInt();
       ResourceGroup g = new ResourceGroup();
       for (int i=0;i<nrResources;i++)
           g.add(Resource.read(in,config));
       return g;
   }
   
   /** Inicializace skupiny po načtení 
    * @param allActivities množina všech aktivit
    */
   protected void init(ActivityGroup allActivities) {
       for (int i=0;i<size();i++)
           get(i).init(allActivities);
   }
   
    /** Zápis skupiny do streamu.
     * @param out stream
     * @param allResources množina všech zdrojů
     */
   protected void write(java.io.ObjectOutputStream out, ResourceGroup allResources) throws java.io.IOException {
       out.writeObject(name);
       out.writeObject(shortCut);
       out.writeObject(note);
       out.writeBoolean(conjunctive);
       out.writeInt(size());
       for (int i=0;i<size();i++)
           get(i).write(out, allResources);
       changed=false;
   }
   
   /** Načtení skupiny ze streamu
    * @param in stream
    * @param config konfigurace
    * @param allResources množina všech zdrojů
    * @return načtená skupina
    */
   protected static ResourceGroup read(java.io.ObjectInputStream in, ResourceGroup allResources) throws java.io.IOException, java.lang.ClassNotFoundException {
       String name=(String)in.readObject();
       String shortCut=(String)in.readObject();
       String note=(String)in.readObject();
       boolean conjunctive=in.readBoolean();
       int nrResources=in.readInt();
       ResourceGroup g = new ResourceGroup();
       g.name=name;g.shortCut=shortCut;g.note=note;g.conjunctive=conjunctive;
       for (int i=0;i<nrResources;i++)
           g.add(Resource.read(in,allResources));
       return g;
   }
   
   /** Vrátí zkratky zdrojů ve skupině jako řetězec. Příklad "{Z1, Z2, Z3}"
    * @return řetězec (ve složených závorkách čárkami oddělené zkratky jmen jednotlivých zdrojů)
    */
   public String toString() {
       StringBuffer b = new StringBuffer();
       b.append("{");
       for (int i=0;i<size();i++) {
           if (i!=0) b.append(", ");
           b.append(get(i).shortCut);
       };
       b.append("}");
       return b.toString();
   }
        
}
