package org.foo.petstore.setup;

import java.io.BufferedReader;
import java.io.FileReader;
import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.foo.petstore.catalog.Category;
import org.foo.petstore.catalog.Inventory;
import org.foo.petstore.catalog.Item;
import org.foo.petstore.catalog.Product;
import org.foo.petstore.catalog.Supplier;
import org.foo.petstore.customer.Account;
import org.foo.petstore.customer.Accounts;
import org.foo.petstore.util.CSValues;

import com.uwyn.rife.authentication.credentialsmanagers.DatabaseUsers;
import com.uwyn.rife.authentication.credentialsmanagers.DatabaseUsersFactory;
import com.uwyn.rife.authentication.credentialsmanagers.RoleUsersManager;
import com.uwyn.rife.cmf.dam.ContentQueryManager;
import com.uwyn.rife.config.Config;
import com.uwyn.rife.database.Datasource;
import com.uwyn.rife.database.Datasources;
import com.uwyn.rife.database.exceptions.DatabaseException;
import com.uwyn.rife.rep.BlockingParticipant;
import com.uwyn.rife.tools.ExceptionUtils;
import com.uwyn.rife.tools.StringEncryptor;


public class Populate extends BlockingParticipant {
    public Populate() {
        super();
    }

	public void cleanup() {
		if (null == datasource) {
			String dsn = Config.getRepInstance().getString("datasource");
			datasource = Datasources.getRepInstance().getDatasource(dsn);
		}

		cleanup(datasource);
	}

	public void cleanup(Datasource dsn) {
	//TODO
	}

	@Override
	public void initialize() {
		Datasources dsns = Datasources.getRepInstance();
		String dsn = Config.getRepInstance().getString("datasource");
		
		
		datasource = dsns.getDatasource(dsn);

		initialize(datasource);
	}

	public void initialize(Datasource ds) {
		assert null != ds;
		
		try {
			cleanup();
		} catch (Exception e) {			
		}
		
		try {
			populateRoles(ds, "user", "admin");
			populateAccounts(ds, "../data/accounts.dat");
			populateCategories(ds, "../data/categories.dat");
			populateProducts(ds, "../data/products.dat");
			populateProductItems(ds, "../data/items.dat");
			populateSuppliers(ds, "../data/suppliers.dat");
			
			ContentQueryManager<Item> items = new ContentQueryManager<Item>(ds, Item.class);
			ContentQueryManager<Inventory> inventory = new ContentQueryManager<Inventory>(ds, Inventory.class);

			for (Item item: items.restore())
				inventory.save(new Inventory(item.getId(), 1000));
			
		} catch (Exception e) {
			Logger.getLogger("org.foo.petstore.populate").severe(ExceptionUtils.getExceptionStackTrace(e));
		}
	}

	protected Object _getObject(Object key) {
		if (((String) key).equals("datasource")) {
			return datasource;
		}
		
		return null;
	}

	private static void populateRoles(Datasource ds, String...roles) {
		RoleUsersManager credentials = DatabaseUsersFactory.getInstance(ds);
		
		for (String role:roles)
			credentials.addRole(role);
	}
	
	private static void populateAccounts(Datasource ds, String filename) {
		DatabaseUsers users = DatabaseUsersFactory.getInstance(ds);
		ContentQueryManager<Account> accounts = new ContentQueryManager<Account>(ds, Account.class);

		try {
			for (CSValues account : generateCSValues(filename))
				accounts.save(createAccount(users, account));
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}


	private static void populateCategories(Datasource ds, String filename) {
		ContentQueryManager<Category> categories = new ContentQueryManager<Category>(ds, Category.class);
				
		try {
			List<CSValues> list = generateCSValues(filename);

			for (CSValues category : list)
				categories.save(createCategory(category));
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	private static void populateProducts(Datasource ds, String filename) {
		ContentQueryManager<Product> products = new ContentQueryManager<Product>(ds, Product.class);
				
		try {
			List<CSValues> list = generateCSValues(filename);

			for (CSValues product : list)
				products.save(createProduct(product));
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	private static void populateProductItems(Datasource ds, String filename) {
		ContentQueryManager<Item> items = new ContentQueryManager<Item>(ds, Item.class);
				
		try {
			List<CSValues> list = generateCSValues(filename);

			for (CSValues item : list)
				items.save(createProductItem(item));
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	private static void populateSuppliers(Datasource ds, String filename) {
		ContentQueryManager<Supplier> suppliers = new ContentQueryManager<Supplier>(ds, Supplier.class);
				
		try {
			List<CSValues> list = generateCSValues(filename);

			for (CSValues supplier : list)
				suppliers.save(createSupplier(supplier));
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	private static Account createAccount(RoleUsersManager users, CSValues data) throws NoSuchAlgorithmException {
		String username = data.item(0);
		String password = StringEncryptor.SHA.encrypt(data.item(1));
		//CSValues roles = new CSValues(data.item(2), "\\|");
		String email = data.item(2);

		Account account = Accounts.create(users, username, password, email, new CSValues("user"));
	
		String firstname = data.item(3);
		String lastname = data.item(4);
		String addr1 = data.item(5);
		String addr2 = data.item(6);
		String city = data.item(7);
		String state = data.item(8);
		String zip = data.item(9);
		String country = data.item(10);
		String phone = data.item(11);
	
		return account.setOptionalValues(firstname, lastname, addr1, addr2, city, state, zip, country, phone);
	}
	

	private static Category createCategory(CSValues data) throws NoSuchAlgorithmException {
		int id = new Integer(data.item(0));
		String name = data.item(1);
		String description = data.item(2);

		return new Category(id, name, description);
	}

	private static Product createProduct(CSValues data) throws NoSuchAlgorithmException {
		int id = new Integer(data.item(0));
		int categoryId = new Integer(data.item(1));
		String name = data.item(2);
		String image = data.item(3);
		String description = data.item(4);
		
		return new Product(id, categoryId, name, image, description);
	}
	
	private static Supplier createSupplier(CSValues data) throws NoSuchAlgorithmException {
		//ID, NAME, ADDRESS1, ADDRESS2, CITY, STATE, ZIP, PHONE
		int id = new Integer(data.item(0));
		String name = data.item(1);
		String addr1 = data.item(2);
		String addr2 = data.item(3);
		String city = data.item(4);
		String state = data.item(5);
		String zip = data.item(6);
		String phone = data.item(7);
		
		return new Supplier(id, name, addr1, addr2, city, state, zip, phone);
	}
	
	private static Item createProductItem(CSValues data) throws NoSuchAlgorithmException {
		//itemid, productid, listprice, unitcost, supplier, attr1
		int id = new Integer(data.item(0));
		int productId = new Integer(data.item(1));
		BigDecimal listPrice = new BigDecimal(data.item(2));
		BigDecimal unitCost = new BigDecimal(data.item(3));
		int supplierId = new Integer(data.item(0));
		String attr1 = data.item(3);

		Item item = new Item(id, supplierId, productId, listPrice, unitCost);
		item.setAttribute1(attr1);
		
		return item;
	}
	
	private static List<CSValues> generateCSValues(String file) throws NoSuchAlgorithmException {
		List<CSValues> list = new ArrayList<CSValues>();	
		BufferedReader br = null;
	
		try {
			br = new BufferedReader(new FileReader(file));
	
			String str;
			br.readLine(); // first line not needed (heading)

			while ((str = br.readLine()) != null) {
				if (!str.equals("")) {
					list.add(new CSValues(str));
				}
			}
		} catch (Exception e) {
			System.err.println("\nerror " + e);
		}
		
		try {
			br.close();
		} catch (Exception e) {
			System.out.println("cannot close " + e);
		}
	
		return list;
	}

	
	private Datasource datasource = null;
}
