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

package timetable.data;

import timetable.util.*;

/** Reprezentace jednoho zdroje v rozvrhovacím problému. 
 *
 * @author Tomáš Müller
 * @version 1.0
 */
public class Resource extends java.lang.Object {
    /** Globální konfigurace */
    protected Config config = null;
    /** Maximální délka zkratky jména */
    public static int SHORT_CUT_MAX_LENGTH = 7;

    /** Zkratka jména - pro vizualizaci */
    public String shortCut = null;
    /** Jméno */
    public String name = null;
    /** Poznámka */
    public String note = null;
    /** Časové preference zdroje */
    protected TimePreference preference = null;
    
    /** Časová tabulka naalokovaných slotů zdroje aktivitami. Slouží zejména k jednoduchému zjištění využívání zdroje v daný časový okamžik.*/
    protected Activity[] table = null;

    /** Indexy časové tabulky, slouží pouze pro čtení a zápis objektu */
    protected int[] tableIndexes = null; // For reading propose only
    
    
    /** Konstruktor.
     * @param config Globální konfigurace
     */
    public Resource(Config config) throws TimetableException {
        this.config=config;
        preference = new TimePreference(config);
        table = new Activity[config.getInt(Config.NR_SLOTS)];
        for (int i=0;i<table.length;i++) table[i]=null;
    }
    
    /** Konstruktor.
     * @param config Globální konfigurace
     * @param shortCut zkratka jména zdroje
     * @param name jméno zdroje
     * @param note poznámka
     */
    public Resource(Config config,String shortCut,String name,String note) throws TimetableException{
        this(config);
        this.name = name;
        this.shortCut=(shortCut==null||shortCut.length()<=SHORT_CUT_MAX_LENGTH?shortCut:shortCut.substring(0,SHORT_CUT_MAX_LENGTH));
        this.note=note;
    }
    
    /** Konstruktor.
     * @param config Globální konfigurace
     * @param name jméno zdroje
     */
    public Resource(Config config,String name) throws TimetableException{
        this(config,name,name,null); 
    }
    
    /** Získání časových preferencí.
     * @return tabluka časových preferencí
     */
    public TimePreference getPreference() {
        return preference;
    }
    
    /** Nastavení tabulky časových preferencí
     * @param preference tabulka časových preferencí
     */
    public void setPreference(TimePreference preference) {
        this.preference=preference;
    }
    
    /** Získání aktivity, naalokované v příslušném slotu.
     * @param slot příslušný časový slot
     * @return naalokovaná aktivita, <code>null</code> pokud je slot volný
     */
    public Activity getActivityAt(int slot) {
        return table[slot];
    }
    
    /** Naalokování slotu pro danou aktivitu.
     * @param slot příslušný časový slot
     * @param activity aktivta, která bude daný zdroj v daném čase využívat
     */
    public void setActivityAt(int slot,Activity activity) {
        table[slot]=activity;
    }

    /** Otázka na využití zdroje v daný časový slot
     * @param slot daný časový slot
     * @return <code>true</code>, pokud je slot volný
     */
    public boolean isFreeAt(int slot) {
        return (!preference.isHARD(slot) && getActivityAt(slot)==null);
    }
    
    /** Otázka, zda-li může být daný slot použit k plánování. Pro takový slot musí platit:
     * <ul><li>na daném slotu není HARD preference</li>
     *<li>slot je volný nebo aktivita, která v něm leží je přeplánovatelná</li>
     *</ul>
     * @param slot příslušný časový slot
     * @return <code>true</code> pokud lze zdroj v daný slot použít
     */
    public boolean canBeFreeAt(int slot) {
        return (!preference.isHARD(slot) && (getActivityAt(slot)==null || getActivityAt(slot).canReschedule));
    }
    
    /** Otázka, zda-li může být daný slot a sloty následující použity k plánování. Pro takové slot musí platit:
     * <ul><li>na daném slotu není HARD preference</li>
     *<li>slot je volný nebo aktivita, která v něm leží je přeplánovatelná</li>
     *</ul>
     * @param slot příslušný časový slot
     * @param length délka aktivity, která chce daný zdroj využívat -> sloty <code>slot .. slot+length-1</code> jsou testovány
     * @return <code>true</code> pokud lze zdroj v dané sloty použít
     */
    public boolean canBeFreeAt(int slot, int length) {
        for (int j=0;j<length;j++) if (!canBeFreeAt(slot+j)) return false;
        return true;
    }
    
    /** Otázka, zda-li je slot v dané časové sloty volný.
     * @param slot příslušný časový slot
     * @param length délka aktivity, která chce daný zdroj využívat -> sloty <code>slot .. slot+length-1</code> jsou testovány
     * @return <code>true</code> pokud je zdroj v dané časové sloty volný
     */
    public boolean isFreeAt(int slot, int length) {
        for (int j=0;j<length;j++) if (!isFreeAt(slot+j)) return false;
        return true;
    }
    
    /** Zjišťuje, zda-li je daná aktivita naplánována konzistentně. To znamená že všechny sloty, které vyžaduje nesmí mít HARD podmínku a musí být pro danou aktivitu alokovány.
     * @param activity daná aktivita
     * @return <code>true</code>, pokud je aktivta naplánována konzistentně (správně)
     */
    public boolean isConsistentFor(Activity activity) {
        for (int i=activity.start;i<activity.start+activity.length;i++) {
            if (preference.isHARD(i) || table[i]!=activity) return false;
        }
        return true;
    }
    
    /** Vrátí množinu aktivit, které využívají daný zdroj v daných časových slotech.
     * @param slot první časový slot
     * @param length délka aktivity, tj. jsou procházeny sloty <code>slot .. slot+length-1</code>
     * @return seznam aktivit využívajících daný zdroj v dané časové sloty
     */
    public ActivityGroup getActivitiesAt(int slot, int length) {
        ActivityGroup ag = new ActivityGroup();
        for (int j=0;j<length;j++) 
            if (getActivityAt(slot+j)!=null) ag.addIfIsNot(getActivityAt(slot+j));
        return ag;
    }
    
    /** Zápis zdroje do objektového streamu. 
     * @param out stream
     * @param allActivities seznam všech aktivit
     */
   protected void write(java.io.ObjectOutputStream out, ActivityGroup allActivities) throws java.io.IOException {
       out.writeObject(shortCut);
       out.writeObject(name);
       out.writeObject(note);
       out.writeObject(preference);
       out.writeInt(table.length);
       for (int i=0;i<table.length;i++) 
           if (getActivityAt(i)!=null) out.writeInt(allActivities.indexOf(getActivityAt(i)));
           else out.writeInt(-1);
   }

   /** Načtení zdroje ze streamu.
    * @param in stream
    * @param config globální konfigurace
    * @return načtený zdroj
    */
   protected static Resource read(java.io.ObjectInputStream in, Config config) throws java.io.IOException, java.lang.ClassNotFoundException,TimetableException {
       Resource z = new Resource(config);
       z.shortCut =  (String) in.readObject();
       z.name =  (String) in.readObject();
       z.note = (String) in.readObject();
       z.preference = (TimePreference) in.readObject();
       z.preference.config=config;
       z.table=null;
       z.tableIndexes = new int[in.readInt()];
       for (int i=0;i<z.tableIndexes.length;i++) z.tableIndexes[i]=in.readInt();
       return z;
   }
   
    /** Zápis zdroje do objektového streamu. 
     * @param out stream
     * @param allResources seznam všech zdrojů
     */
   protected void write(java.io.ObjectOutputStream out, ResourceGroup allResources) throws java.io.IOException {
       out.writeInt(allResources.indexOf(this));
   }

   /** Načtení zdroje ze streamu.
    * @param in stream
    * @param allResources seznam všech zdrojů
    * @return načtený zdroj
    */
   protected static Resource read(java.io.ObjectInputStream in, ResourceGroup allResources) throws java.io.IOException {
       return allResources.get(in.readInt());
   }
   
   /** Inicializace zdroje po jeho načtení*/
   protected void init(ActivityGroup allActivities) {
      if (tableIndexes==null) return;
      table = new Activity[tableIndexes.length];
      for (int i=0;i<table.length;i++) 
          if (tableIndexes[i]==-1) table[i]=null;
          else table[i]=allActivities.get(tableIndexes[i]);
      tableIndexes=null;
   }
   
   /** Vrací zkratku jména zdroje. 
    * @return zkratka jména zdroje 
    */
   public String toString() {
       return shortCut;
   }

}
