package data.stdforms.twotableformsheet;

import data.*;
import data.stdforms.*;

import sale.*;

import users.*;

/**
  * MoveStrategy for a CountingStock source and a DataBasket destination.
  *
  * @author Steffen Zschaler
  * @version 2.0 20/08/1999
  * @since v2.0
  */
public class CSDBStrategy extends MoveStrategy {

  /**
    * Get the sub-process that will move items from the source to the destination.
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param ci the CatalogItem that is selected in the source.
    * @param nCount the number of items to be moved.
    * @param ttfs the FormSheet that triggers the process.
    *
    * @override Never
    */
  public Transition getMoveToDestProcess (SaleProcess p,
                                          SalesPoint sp,
                                          CountingStock csSource,
                                          DataBasket dbDest,
                                          CatalogItem ci,
                                          int nCount,
                                          TwoTableFormSheet ttfs) {
    return new GateChangeTransition (getCheckMoveToDestGate (p, sp, csSource, dbDest, ci, nCount, ttfs));
  }

  /**
    * Get the first gate of the sub-process that will move items from the source to the destination.
    *
    * <p>This Gate will check whether the move is allowable, and if so, will trigger a Transition that
    * performs it.</p>
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param ci the CatalogItem that is selected in the source.
    * @param nCount the number of items to be moved.
    * @param ttfs the FormSheet that triggers the process.
    *
    * @override Never Instead, override {@link #checkMoveToDest} and/or {@link #moveToDest}.
    */
  protected Gate getCheckMoveToDestGate (SaleProcess p,
                                         final SalesPoint sp,
                                         final CountingStock csSource,
                                         final DataBasket dbDest,
                                         final CatalogItem ci,
                                         final int nCount,
                                         final TwoTableFormSheet ttfs) {
    return new Gate() {
      public Transition getNextTransition (SaleProcess p, User u)
        throws InterruptedException {
        int nCheckResult = checkMoveToDest (p, sp, csSource, dbDest, ci, nCount);

        if (nCheckResult == 0) {
          return new Transition() {
            public Gate perform (SaleProcess p, User u) {
              moveToDest (p, sp, csSource, dbDest, ci, nCount);

              return ttfs.getGate();
            }
          };
        }
        else {
          error (p, nCheckResult);

          return new GateChangeTransition (ttfs.getGate());
        }
      }
    };
  }

  /**
    * Check whether the indicated move is allowable. If so, return 0, otherwise return a non-zero error value
    * that can be passed on to {@link sale.stdforms.FormSheetStrategy#error}. You can assume that you are at a {@link Gate}.
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param ci the CatalogItem that is selected in the source.
    * @param nCount the number of items to be moved.
    *
    * @override Sometimes The default implementation returns 0.
    */
  protected int checkMoveToDest (SaleProcess p,
                                 SalesPoint sp,
                                 CountingStock csSource,
                                 DataBasket dbDest,
                                 CatalogItem ci,
                                 int nCount)
    throws InterruptedException {
    return 0;
  }

  /**
    * Move the indicated number of items as indicated into the destination DataBasket. You can assume that you
    * are in a {@link Transition}.
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param ci the CatalogItem that is selected in the source.
    * @param nCount the number of items to be moved.
    *
    * @override Sometimes
    */
  protected void moveToDest (SaleProcess p,
                             SalesPoint sp,
                             CountingStock csSource,
                             DataBasket dbDest,
                             CatalogItem ci,
                             int nCount) {
    try {
      csSource.remove (ci.getName(), nCount, dbDest);
    }
    catch (NotEnoughElementsException neee) {
      error (p, NOT_ENOUGH_ELEMENTS_ERROR);
    }
    catch (data.events.VetoException ve) {
      error (p, REMOVE_VETO_EXCEPTION);
    }
  }

  /**
    * Get the sub-process that will move items from the destination to the source.
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param dbe the DataBasketEntry that is selected in the destination.
    * @param nCount the number of items to be moved.
    * @param ttfs the FormSheet that triggers the process.
    *
    * @override Never
    */
  public Transition getMoveToSourceProcess (SaleProcess p,
                                            SalesPoint sp,
                                            CountingStock csSource,
                                            DataBasket dbDest,
                                            DataBasketEntry dbe,
                                            int nCount,
                                            TwoTableFormSheet ttfs) {
    return new GateChangeTransition (getCheckMoveToSourceGate (p, sp, csSource, dbDest, dbe, nCount, ttfs));
  }

  /**
    * Get the first gate of the sub-process that will move items from the destination to the source.
    *
    * <p>This Gate will check whether the move is allowable, and if so, will trigger a Transition that
    * performs it.</p>
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param dbe the DataBasketEntry that is selected in the destination.
    * @param nCount the number of items to be moved.
    * @param ttfs the FormSheet that triggers the process.
    *
    * @override Never Instead, override {@link #checkMoveToSource} and/or {@link #moveToSource}.
    */
  protected Gate getCheckMoveToSourceGate (SaleProcess p,
                                           final SalesPoint sp,
                                           final CountingStock csSource,
                                           final DataBasket dbDest,
                                           final DataBasketEntry dbe,
                                           final int nCount,
                                           final TwoTableFormSheet ttfs) {
    return new Gate() {
      public Transition getNextTransition (SaleProcess p, User u)
        throws InterruptedException {
        int nCheckResult = checkMoveToSource (p, sp, csSource, dbDest, dbe, nCount);

        if (nCheckResult == 0) {
          return new Transition() {
            public Gate perform (SaleProcess p, User u) {
              moveToSource (p, sp, csSource, dbDest, dbe, nCount);

              return ttfs.getGate();
            }
          };
        }
        else {
          error (p, nCheckResult);

          return new GateChangeTransition (ttfs.getGate());
        }
      }
    };
  }

  /**
    * Check whether the indicated move is allowable. If so, return 0, otherwise return a non-zero error value
    * that can be passed on to {@link sale.stdforms.FormSheetStrategy#error}. You can assume that you are at a {@link Gate}.
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param dbe the DataBasketEntry that is selected in the destination.
    * @param nCount the number of items to be moved.
    *
    * @override Sometimes The default implementation returns
    * {@link ProcessErrorCodes#NOT_ENOUGH_ELEMENTS_ERROR} if yoy try to move more elements than are available
    * in the DataBasketEntry.
    */
  protected int checkMoveToSource (SaleProcess p,
                                   SalesPoint sp,
                                   CountingStock csSource,
                                   DataBasket dbDest,
                                   DataBasketEntry dbe,
                                   int nCount)
    throws InterruptedException {

    if (nCount <= ((Number) dbe.getValue()).intValue()) {
      return 0;
    }
    else {
      return NOT_ENOUGH_ELEMENTS_ERROR;
    }
  }

  /**
    * Move the indicated number of items as indicated from the source into the destination. You can assume that
    * you are in a {@link Transition}.
    *
    * @param p the process into which the sub-process wil be embedded.
    * @param sp the SalesPoint, if any, at which the FormSheet is being displayed.
    * @param csSource the source CountingStock.
    * @param dbDest the destination DataBasket.
    * @param dbe the DataBasketEntry that is selected in the destination.
    * @param nCount the number of items to be moved.
    *
    * @override Sometimes
    */
  protected void moveToSource (SaleProcess p,
                               SalesPoint sp,
                               CountingStock csSource,
                               DataBasket dbDest,
                               DataBasketEntry dbe,
                               int nCount) {
    csSource.add (dbe.getSecondaryKey(), nCount, dbDest);
  }
}