package com.ibatis.jpetstore.domain.logic;

import com.ibatis.common.resources.*;
import com.ibatis.common.util.*;
import com.ibatis.db.dao.*;
import com.ibatis.jpetstore.domain.*;
import com.ibatis.jpetstore.persistence.dao.iface.*;

import java.util.*;
import java.io.*;

public class PetStoreLogic {

  /* Constants */

  private static final PetStoreLogic instance = new PetStoreLogic();

  /* Private Fields */

  private boolean useSimpleConfiguration;

  private DaoManager storeDaoManager;
  private DaoManager orderDaoManager;

  private AccountDao accountDao;
  private CategoryDao categoryDao;
  private ItemDao itemDao;
  private OrderDao orderDao;
  private ProductDao productDao;
  private SequenceDao sequenceDao;

  /* Constructors */

  private PetStoreLogic() {
    try {
      Properties props = new Properties();
      props.load(Resources.getResourceAsStream("properties/petstore.properties"));

      String resource = null;
      useSimpleConfiguration = Boolean.valueOf(props.getProperty("useSimpleConfiguration")).booleanValue();
      if (useSimpleConfiguration) {
        resource = "properties/simple/dao.xml";
        System.out.println ("Using SIMPLE configuration. ("+resource+")");
      } else {
        resource = "properties/distributed/dao.xml";
        System.out.println ("Using DISTRIBUTED configuration. ("+resource+")");
      }

      Reader reader = Resources.getResourceAsReader(resource);
      DaoManager.configure(reader);

      storeDaoManager = DaoManager.getInstance("StoreDaoManager");
      if (useSimpleConfiguration) {
        orderDaoManager = storeDaoManager;
      } else {
        orderDaoManager = DaoManager.getInstance("OrderDaoManager");
      }

      accountDao = (AccountDao) storeDaoManager.getDao("Account");
      categoryDao = (CategoryDao) storeDaoManager.getDao("Category");
      productDao = (ProductDao) storeDaoManager.getDao("Product");
      itemDao = (ItemDao) storeDaoManager.getDao("Item");
      sequenceDao = (SequenceDao) storeDaoManager.getDao("Sequence");
      orderDao = (OrderDao) orderDaoManager.getDao("Order");

    } catch (Exception e) {
      throw new RuntimeException("Could not initialize BaseLogic.  Cause: " + e);
    }

  }

  /* Public Methods */

  public static PetStoreLogic getInstance() {
    return instance;
  }

  /* ACCOUNT */

  public Account getAccount(String username) throws DaoException {
    Account account = null;
    try {
      storeDaoManager.startTransaction();
      account = accountDao.getAccount(username);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return account;
  }

  public Account getAccount(String username, String password) throws DaoException {
    Account account = null;
    try {
      storeDaoManager.startTransaction();
      account = accountDao.getAccount(username, password);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return account;
  }

  public void insertAccount(Account account) throws DaoException {
    try {
      storeDaoManager.startTransaction();

      accountDao.insertAccount(account);

      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
  }

  public void updateAccount(Account account) throws DaoException {
    try {
      storeDaoManager.startTransaction();

      accountDao.updateAccount(account);

      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
  }

  public List getUsernameList() throws DaoException {
    List list = null;
    try {
      storeDaoManager.startTransaction();
      list = accountDao.getUsernameList();
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return list;
  }

  /* CATEGORY */

  public List getCategoryList() throws DaoException {
    List list = null;
    try {
      storeDaoManager.startTransaction();
      list = categoryDao.getCategoryList();
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return list;
  }

  public Category getCategory(String categoryId) throws DaoException {
    Category category = null;
    try {
      storeDaoManager.startTransaction();
      category = categoryDao.getCategory(categoryId);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return category;
  }

  /* PRODUCT */

  public Product getProduct(String productId) throws DaoException {
    Product product = null;
    try {
      storeDaoManager.startTransaction();
      product = productDao.getProduct(productId);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return product;
  }

  public PaginatedList getProductListByCategory(String categoryId) throws DaoException {
    PaginatedList list = null;
    try {
      storeDaoManager.startTransaction();
      list = productDao.getProductListByCategory(categoryId);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return list;
  }

  public PaginatedList searchProductList(String keywords) throws DaoException {
    PaginatedList list = null;
    try {
      storeDaoManager.startTransaction();
      list = productDao.searchProductList(keywords);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return list;
  }

  /* ITEM */

  public List getItemListByProduct(String productId) throws DaoException {
    List list = null;
    try {
      storeDaoManager.startTransaction();
      list = itemDao.getItemListByProduct(productId);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return list;
  }

  public Item getItem(String itemId) throws DaoException {
    Item item = null;
    try {
      storeDaoManager.startTransaction();
      item = itemDao.getItem(itemId);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return item;
  }

  public boolean isItemInStock(String itemId) throws DaoException {
    boolean b = false;
    try {
      storeDaoManager.startTransaction();
      b = itemDao.isItemInStock(itemId);
      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return b;
  }

  /* ORDER */

  public void insertOrder(Order order) throws DaoException {
    int orderId = getNextId("ordernum");
    order.setOrderId(orderId);
    if (useSimpleConfiguration) {
      doSimpleInsertOrder(order);
    } else {
      doDistributedInsertOrder(order);
    }
  }

  private void doSimpleInsertOrder(Order order) throws DaoException {
    try {
      storeDaoManager.startTransaction();

      itemDao.updateQuantity(order);
      orderDao.insertOrder(order);

      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
  }

  private void doDistributedInsertOrder(Order order) throws DaoException {
    try {
      orderDaoManager.startTransaction();
      storeDaoManager.startTransaction();

      orderDao.insertOrder(order);
      itemDao.updateQuantity(order);

      if ("ACID".equals(order.getUsername())) {
        throw new DaoException("ACID user detected.  Say no to drugs!  Forcing the transaction to fail.");
      }

      storeDaoManager.commitTransaction();
      orderDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      try { orderDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }

  }

  public Order getOrder(int orderId) throws DaoException {
    Order order = null;

    try {
      orderDaoManager.startTransaction();
      if (!storeDaoManager.isTransactionStarted()) {
        storeDaoManager.startTransaction();
      }

      order = orderDao.getOrder(orderId);

      for (int i = 0; i < order.getLineItems().size(); i++) {
        LineItem lineItem = (LineItem) order.getLineItems().get(i);
        lineItem.setItem(itemDao.getItem(lineItem.getItemId()));
      }

      storeDaoManager.commitTransaction();
      if (orderDaoManager.isTransactionStarted()) {
        orderDaoManager.commitTransaction();
      }
    } catch (DaoException e) {
      try { orderDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }

    return order;
  }

  public List getOrdersByUsername(String username) throws DaoException {
    List list = null;
    try {
      orderDaoManager.startTransaction();
      list = orderDao.getOrdersByUsername(username);
      orderDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { orderDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }
    return list;
  }

  /* SEQUENCE */

  public synchronized int getNextId(String key) throws DaoException {
    int nextId = -1;

    try {
      storeDaoManager.startTransaction();

      nextId = sequenceDao.getNextId(key);

      storeDaoManager.commitTransaction();
    } catch (DaoException e) {
      try { storeDaoManager.rollbackTransaction(); } catch (Exception e2) { /* ignore */ }
      throw ((DaoException) e.fillInStackTrace());
    }

    return nextId;
  }
}