package data.stdforms.singletableformsheet;

import sale.*;
import sale.stdforms.*;

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

import users.*;

/**
  * A strategy that can be attached to the {@link SingleTableFormSheet#addAddButton "Add" button} of
  * a {@link SingleTableFormSheet} that displays a {@link Catalog Catalog's} contents.
  *
  * <p>This strategy is <i>abstract</i> since the creation of the {@link CatalogItem} is application specific.
  * It must be defined by overriding {@link #createCatalogItem}.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 20/08/1999
  * @since v2.0
  */
public abstract class AbstractAddCatalogItemStrategy extends EditButtonStrategy {

  /**
    * The resource bundle key of the label to be shown in the &quot;Define Key&quot; FormSheet.
    */
  public static final String KEY_LABEL = "singletableformsheet.abstractaddcatalogitemstrategy.key_label";

  /**
    * The Catalog to be edited.
    *
    * @serial
    */
  protected Catalog m_cCatalog;

  /**
    * Create a new AbstractAddCatalogItemStrategy.
    *
    * @param c the Catalog to be edited. Must be the same that is displayed in the {@link SingleTableFormSheet}.
    */
  public AbstractAddCatalogItemStrategy (Catalog c) {
    super();

    m_cCatalog = c;
  }

  /**
    * @override Never
    */
  public Transition getEditProcess (SingleTableFormSheet stfs, SaleProcess p, SalesPoint sp) {
    return new GateChangeTransition (getCreateCIGate (stfs));
  }

  /**
    * Get the first Gate in the sub-process. This Gate asks the user for the key of the new item, creates it in
    * a new Transition and after editing the new item adds it to the Catalog.
    *
    * @override Never Instead, override {@link #getNewKey}, {@link #createCatalogItem}, {@link #getEditCIGate}
    * and/or {@link #addToCatalog}.
    *
    * @param stfs the FormSheet that triggered the sub-process.
    */
  protected Gate getCreateCIGate (final SingleTableFormSheet stfs) {
    return new Gate() {
      public Transition getNextTransition (SaleProcess p, User u)
        throws InterruptedException {
        final String sKey = getNewKey (stfs, p);

        if (sKey != null) {
          return new Transition() {
            public Gate perform (SaleProcess _p, User _u) {
              // create the CatalogItem
              final CatalogItem ci = createCatalogItem (sKey);

              return getEditCIGate (ci, stfs, new Transition() {
                public Gate perform (SaleProcess __p, User __u) {
                  addToCatalog (__p, ci);

                  return stfs.getGate();
                }
              });
            }
          };
        }
        else {
          return new GateChangeTransition (stfs.getGate());
        }
      }
    };
  }

  /**
    * Get the key of the new item. Can assume that at a Gate.
    *
    * @override Sometimes The default implementation pops up a FormSheet where the user can enter a new
    * key.
    *
    * @param stfs the FormSheet that triggered the sub-process.
    * @param p the process into which the sub-process was embedded.
    */
  protected String getNewKey (SingleTableFormSheet stfs, SaleProcess p)
    throws InterruptedException {
    TextInputForm fs = new TextInputForm (stfs.getCaption(),
                                          getResourceString (KEY_LABEL),
                                          "");

    p.getContext().popUpFormSheet (p, fs);

    return ((fs.isCancelled())?(null):(fs.getText()));
  }

  /**
    * Create a new CatalogItem of the given key.
    *
    * @override Always The contents of this method is application specific.
    *
    * @param sKey the key for which to create a new CatalogItem.
    *
    * @return the new CatalogItem.
    */
  protected abstract CatalogItem createCatalogItem (String sKey);

  /**
    * Get a Gate at which a newly created CatalogItem can be edited by the user.
    *
    * @param ci the CatalogItem to be edited.
    * @param stfs the FormSheet that triggered the sub-process. A transition to this FormSheet's gate must be
    * leaving the Gate if the user cancels the operation.
    * @param tOk the Transition that must be leaving the Gate if the user finished editing and did not cancel
    * the operation or enter invalid data.
    *
    * @override Sometimes The default implementation simply continues with <code>tOk</code>.
    */
  protected Gate getEditCIGate (CatalogItem ci,
                                SingleTableFormSheet stfs,
                                final Transition tOk) {
    return new Gate() {
      public Transition getNextTransition (SaleProcess p, User u) {
        return tOk;
      }
    };
  }

  /**
    * Add the specified CatalogItem to the Catalog.
    *
    * <p>Any error condition should be passed on to {@link FormSheetStrategy#error} in
    * {@link FormSheetStrategy}.</p>
    *
    * @param p the process into which the sub-process was embedded.
    * @param ci the CatalogItem to be added to the Catalog.
    *
    * @override Never
    */
  protected void addToCatalog (SaleProcess p,
                               CatalogItem ci) {
    try {
      m_cCatalog.add (ci, p.getBasket());
    }
    catch (DuplicateKeyException dke) {
      error (p, DUPLICATE_KEY_EXCEPTION);
    }
    catch (DataBasketConflictException dbce) {
      error (p, DATABASKET_CONFLICT_ERROR);
    }
  }

  /**
    * Get the resource String for the specified key.
    *
    * @override Sometimes The default implementation returns
    * &quot;"Please specify the CatalogItem's key:"&quot; if asked for {@link #KEY_LABEL}.
    */
  protected String getResourceString (String sKey) {
    if (sKey.equals (KEY_LABEL)) {
      return "Please specify the CatalogItem's key:";
    }
    else {
      return "[" + sKey + " not defined!]";
    }
  }
}