import sale.*;
import sale.stdforms.*;
import data.*;
import data.ooimpl.*;
import data.stdforms.*;
import data.events.*;
import users.*;
import log.*;

import java.util.*;
import java.text.*;
import java.lang.*;
import java.io.*;

import javax.swing.JTextField;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.BoxLayout;
import javax.swing.JLabel;



/**
 * Rückgabeprocess, der von einem registrierten Kunden
 * am Automaten durchgeführt werden kann.
 */
public class GiveBackProcess extends SaleProcess
{
   
  //// attributes ////////////////////////////////////////////////////////////
   
  // Gates
  protected UIGate capabilityGate;
  protected UIGate selectionGate;
  protected UIGate giveRestGate;
  
  // Transitions
  protected Transition toSelectionTransition;
  protected Transition toGetMoneyTransition;
  
  // verwendete Waehrung
  protected Currency myCurrency;
   
  // rueckzuzahlender Betrag
  private int toPayBackValue;
   
  // gezahlter Betrag (Verkaufspreis des Videos)
  private IntegerValue paidValue;
   
  // Kunde, der zurueckgeben moechte
  private Customer customer;
   
  // Verleihpreis eines Videos pro Tag
  private int rentPrice = 300;
   
   
  //// constructor ///////////////////////////////////////////////////////////
   
  /**
   * Erzeugt ein neues Objekt der Klasse GiveBackProcess.
   */
  public GiveBackProcess()
  {
    super ("GiveBackProcess");
  }
   
  //// protected methods /////////////////////////////////////////////////////
   
  /**
   * Baut die Oberfläche für den Rückgabevorgang auf.
   */
  protected void setupMachine()
  {
    // verwendete Waehrung ermitteln
    myCurrency = (Currency)Shop.getTheShop().getCatalog("DM");
      
    // Videokatalog
    final CatalogImpl videoCatalog =
      (CatalogImpl)Shop.getTheShop().getCatalog("Video-Catalog");
      
    // zu verwendenden Datenkorb ermitteln
    final DataBasket db = getBasket();
      
      
    //////////////////////////////////////////////////
    /// Capability-Gate //////////////////////////////
    //////////////////////////////////////////////////
      
      
    // Formsheet fuer Eingabe der Kundennummer
    // tif ist final, damit in der anonymen Klasse des FSCC auf Attribute des tif zugegriffen werden kann
    final TextInputForm tif = new TextInputForm("Customer-ID",
                                                "Customer-ID",
                                                "");
      
    // FormSheetContentCreator fuer Capability-Gate implementieren       
    tif.addContentCreator(
      new FormSheetContentCreator()
      {
        protected void createFormSheetContent(FormSheet fs)
        {
          // alle vorhandenen Buttons entfernen
          fs.removeAllButtons();
                                    
          // neuen "OK"-Button einbauen
          fs.addButton ("Ok", 100, 
            new sale.Action()
            {
              public void doAction (SaleProcess p, SalesPoint sp)
              {
                // Eingabe ueberpruefen
                String customerID = tif.getText();
                boolean isNotAnInteger = true;
                                                          
                try {
                  new Integer(customerID);
                  isNotAnInteger = false;
                }                                                            
                catch (NumberFormatException nfe) {
                }
                // Eingabe korrekt -> selectionGate
                if (!isNotAnInteger && (new Integer(customerID)).intValue() > 0) {
                                                             
                  // existiert der Kunde?
                  try {
                    boolean customerExists = false;
                    Set customerSet = VideoMachine.getAllCustomer();
                    Iterator i = customerSet.iterator();
                    while (i.hasNext() && !customerExists) {
                      Customer myCustomer = (Customer)i.next();
                      if (myCustomer.getCustomerID().equals(customerID)) {
                        customer = myCustomer;
                        customerExists = true;
                      }
                    }
                                                                
                    if (customerExists) {
                      capabilityGate.setNextTransition(toSelectionTransition);
                    }
                    else {
                      JOptionPane.showMessageDialog(null, "This CustomerID doesn't exist!");
                      capabilityGate.setNextTransition(
                        new GateChangeTransition(capabilityGate));
                    }
                  }                                                      
                  catch (NullPointerException ne) {
                    JOptionPane.showMessageDialog(null, "No videos rent out!");
                    new GateChangeTransition(capabilityGate);
                  }
                }                                               
                // Eingabe falsch -> Kunden informieren und
                // Eingabe wiederholen
                else {
                  JOptionPane.showMessageDialog(null, "CustomerID must be a positive number!");
                  capabilityGate.setNextTransition(
                    new GateChangeTransition(capabilityGate));
                }
              }
            }
          );
                                    
          // "Cancel"-Button einbauen
          fs.addButton ("Cancel", 101, 
            new sale.Action()
              {
                public void doAction (SaleProcess p, SalesPoint sp)
                {
                  // Transition zum Rollback-Gate als naechste Transition setzen
                  capabilityGate.setNextTransition(
                    GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
                }
              }
          );
        }
      }
    );
      
    // Gate zur Kundennummer-Abfrage anlegen
    capabilityGate = new UIGate((FormSheet) tif, 
                                (MenuSheet) null);
      
      
    //////////////////////////////////////////////////
    /// Selection-Gate ///////////////////////////////
    //////////////////////////////////////////////////
      
      
    // Auswahl-Gate anlegen
    // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
    selectionGate = new UIGate((FormSheet) null, (MenuSheet) null);
      
    // Transition zum Selection Gate
    toSelectionTransition = 
      new Transition()
      {
        public Gate perform(SaleProcess pOwner, User usr)
        {
          // zu verwendenden Bestand ermitteln
          StoringStock ss = customer.getStoringStock();
                  
          // am Gate darzustellendes FormSheet
          TwoTableFormSheet ttfs = 
            TwoTableFormSheet.create("Give Back",           // Titel des FormSheets
                                     ss,                    // Quell-StoringStock
                                     db,                    // Ziel-DataBasket
                                     selectionGate          // Gate, an dem das FormSheet darzustellen ist
                                     );
                  
          // FormSheetContentCreator am Auswahl-Gate anmelden    
          ttfs.addContentCreator(
            new FormSheetContentCreator()
            {
              protected void createFormSheetContent(FormSheet fs)
              {
                // alle vorhandenen Buttons entfernen
                fs.removeAllButtons();
                                               
                // neuen "OK"-Button einbauen
                fs.addButton ("Ok", 100, 
                  new sale.Action()
                  {
                    public void doAction (SaleProcess p, SalesPoint sp)
                    {
                      // Transition zum Bezahlen als naechste Transition setzen
                      selectionGate.setNextTransition(toGetMoneyTransition);
                    }
                  }
                );
                              
                // "Cancel"-Button einbauen
                fs.addButton ("Cancel", 101, 
                  new sale.Action()
                  {
                    public void doAction (SaleProcess p, SalesPoint sp)
                    {
                      // Transition zum Rollback-Gate als naechste Transition setzen
                      selectionGate.setNextTransition(
                        GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
                    }
                  }
                );
              }
            }
          );
                  
          // erstelltes FormSheet am zu betretenden Gate setzen
          selectionGate.setFormSheet(ttfs);
                 
          // als naechstes zu betretendes Gate zurueckgeben
          return selectionGate;
        }
      };
      
      
    //////////////////////////////////////////////////
    /// GiveRest-Gate ////////////////////////////////
    //////////////////////////////////////////////////
     
      
    // Gate zum Ausgeben des Restgeldes anlegen
    // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
    giveRestGate = new UIGate(null, null);
     
    // Transition zum Gate, an dem das Restgeld gegeben wird
    toGetMoneyTransition = 
      new Transition()
      {
        public Gate perform(SaleProcess pOwner, User usr)
        {
          // Parameter zum Aufsummieren des Datenkorbes festlegen
          DataBasketCondition dbc =
            DataBasketConditionImpl.ALL_STOCK_ITEMS;
          int sellValue = 0;
          int rentValue = 0;
                  
          // Videobestand des Automaten
          CountingStockImpl videoStock =
            (CountingStockImpl)Shop.getTheShop().getStock("Video-Countingstock");
                  
          // aktuelle Zeit ermitteln
          Object date = Shop.getTheShop().getTimer().getTime();
                  
          // rueckzuzahlenden Betrag ermitteln
          Iterator i = db.iterator(dbc);
            
          while (i.hasNext()) 
          {         
            // spezielle Kassette ermitteln
            StoringStockItemDBEntry cassetteItem = 
              (StoringStockItemDBEntry)i.next();
            CassetteStoringStockItem cassette = 
              (CassetteStoringStockItem)cassetteItem.getValue();
                     
            // Verkaufspreis bestimmen
            try {
              sellValue =
                ((NumberValue)((QuoteValue)(videoCatalog.get(
                  cassette.getName(), null, false).getValue())).getBid()
                    ).getValue().intValue();
            }
            catch (VetoException ve) {
            }
                    
            // mind. einen Tag ausgeliehen?
            if ((((Long)date).intValue()
              - ((Long)cassette.getDate()).intValue()) > 0) 
            {
              // Verleihgebuehr bestimmen
              rentValue = (((Long)date).intValue()
                - ((Long)cassette.getDate()).intValue()) * rentPrice;
                                               
              // Leihgebuehr kleiner als Verkaufspreis?
              if (rentValue < sellValue) {
                //rueckzuzahlenden Betrag erhoehen
                toPayBackValue = toPayBackValue + (sellValue - rentValue);
                           
                // Video in Automatenbestand zuruecklegen
                videoStock.add(cassette.getName(), 1, null);
              }                                
              // Leihgebuehr groesser als Verkaufspreis
              else {
                JOptionPane.showMessageDialog(null,
                  cassette.getName() + " is your's!");
              }                       
            }
                     
            // keinen Tag ausgeliehen (trotzdem 3,00 DM Leihgebuehr)
            if ((((Long)date).intValue()
              - ((Long)cassette.getDate()).intValue()) == 0) 
            {          
              //rueckzuzahlenden Betrag erhoehen
              toPayBackValue = toPayBackValue + (sellValue - rentPrice);
                        
              // Video in Automatenbestand zuruecklegen
              videoStock.add(cassette.getName(), 1, null);
            }
          }
                  
          // ueberpruefen, ob der Kunde noch Videos im Bestand hat
          if (customer.getStoringStock().size(null) == 0)
            VideoMachine.removeCustomer(customer);
                  
          // rueckzugebenden Betrag vom Geldbestand abziehen
          try 
          {
            if (toPayBackValue > 0 ) 
            {
              ((CountingStock)Shop.getTheShop().getStock(
                 "coin slot")).remove(CurrencyImpl.PFENNIG_STCK_1,
                    toPayBackValue, pOwner.getBasket());
            }
          }
          catch (VetoException ve) {
          }
                 
          // am Gate darzustellendes FormSheet
          MsgForm mf = new MsgForm("Give Rest",
                                   "You get " +
                                   myCurrency.toString(new IntegerValue(toPayBackValue)) +
                                   " back");
                  
          // ContentCreator zur Neubelegung des "OK"-Buttons hinzufuegen 
          mf.addContentCreator(
            new FormSheetContentCreator()
            {
              public void createFormSheetContent(FormSheet fs)
              {
                // neue Aktion setzen
                fs.getButton(FormSheet.BTNID_OK).setAction(
                  new Action()
                  {
                    public void doAction(SaleProcess p, SalesPoint sp)
                    {
                    // zum Commit-Gate fuehrende Transition als
                    // naechste Transition setzen
                    giveRestGate.setNextTransition(
                      GateChangeTransition.CHANGE_TO_COMMIT_GATE);
                    }
                  }
                );
              }
            } 
         ); 
                  
         // erstelltes FormSheet am zu betretenden Gate setzen
         giveRestGate.setFormSheet(mf);
                 
         // als naechstes zu betretendes Gate zurueckgeben
         return giveRestGate;
       }
     };
   }
   
   
   //// public methods ////////////////////////////////////////////////////////
   
   /**
    * Gibt das Startgate des Prozesses zur&uuml;ck.
    */
   public Gate getInitialGate()
   {  
     // Automat aufbauen
     setupMachine();
      
     // ...und Capability-Gate als Startgate zurueckgeben
     return capabilityGate;
   }
   
   /**
    * &Uuml;bergibt das Log-Gate. Hier das Stop-Gate, da beim Beenden des
    * Prozesses kein Log-Eintrag geschrieben werden soll.
    */
   public Gate getLogGate()
   {
     return getStopGate();
   }
}