package com.manning.aip.portfolio;

import java.util.ArrayList;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;

/**
 * Obiekt do utrwalania i pobierania danych na temat akcji. Do utrwalania i pobierania
 * służy baza SQLite.
 * 
 * @author Michael Galpin
 *
 */
public class StocksDb {
	private static final String TAG = "StocksDb";
	// Metadane dotyczące bazy
	private static final String DB_NAME = "stocks.db";
	private static final int DB_VERSION = 1;
	
	private static final String TABLE_NAME = "stock";
	
	// Nazwy kolumn
	private static final String ID = "id";
	private static final String SYMBOL = "symbol";
	private static final String MAX_PRICE = "max_price";
	private static final String MIN_PRICE = "min_price";
	private static final String PRICE_PAID = "price_paid";
	private static final String QUANTITY = "quantity";
	private static final String CURRENT_PRICE = "current_price";
	private static final String NAME = "name";

	// Instrukcje w SQL-u
	private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
			" ("+ID+" INTEGER PRIMARY KEY, "+SYMBOL+" TEXT, "+
			MAX_PRICE+" DECIMAL(8,2), " + MIN_PRICE+" DECIMAL(8,2), " +
			PRICE_PAID+ " DECIMAL(8,2), " + QUANTITY + " INTEGER, " +
			CURRENT_PRICE + " DECIMAL(8,2), "+NAME+" TEXT)";
	private static final String INSERT_SQL = "INSERT INTO " + TABLE_NAME +
			" ("+SYMBOL+", "+MAX_PRICE+", "+MIN_PRICE+", "+PRICE_PAID+
			", "+QUANTITY+", " + CURRENT_PRICE+", "+NAME+") " +
			"VALUES (?,?,?,?,?,?,?)";
	private static final String READ_SQL = "SELECT "+ID+", "+SYMBOL+", " +
			MAX_PRICE+", " + MIN_PRICE +", "+PRICE_PAID+", "+ 
			QUANTITY+", " +CURRENT_PRICE+ ", "+NAME+" FROM " + 
			TABLE_NAME;
	private static final String UPDATE_SQL = "UPDATE " + TABLE_NAME + 
		" SET "+CURRENT_PRICE+"=? WHERE "+ID+"=?";
	
	// Obiekt klasy Context użyty do utworzenia bazy StocksDb
	private final Context context;
	private final SQLiteOpenHelper helper;
	private  SQLiteStatement stmt;
	private  SQLiteStatement updateStmt;
	private final SQLiteDatabase db;

	/**
	 * Konstruktor przyjmujący obiekt klasy <code>Context</code>, zwykle powiązany z
	 * usługą lub aktywnością tworzącą dany egzemplarz.
	 * Ten konstruktor inicjuje obiekt klasy SQLiteOpenHelper używany dla
	 * bazy i wstępnie kompiluje SQL-owe instrukcje insert i update.
	 * 
	 * @param 	ctx			Obiekt klasy <code>Context</code> generujący dany egzemplarz
	 */
	public StocksDb(Context ctx){
		context = ctx;
		
		// Inicjowanie obiektu pomocniczego do obsługi bazy danych
		helper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION){
			@Override
			public void onCreate(SQLiteDatabase db) {
				db.execSQL(CREATE_TABLE);
				Log.d(TAG, "Utworzono tabelę: \n" + CREATE_TABLE);
			}

			@Override
			public void onUpgrade(SQLiteDatabase db, int oldVersion, 
					int newVersion) {
				throw new UnsupportedOperationException();
			}
		};
		
		// Otwieranie bazy danych.
		db = helper.getWritableDatabase();
		
		// Wstępne kompilowanie instrukcji.
		stmt = db.compileStatement(INSERT_SQL);
		updateStmt = db.compileStatement(UPDATE_SQL);
	}
	
	/**
	 * Zapisuje obiekt klasy <code>Stock</code> w bazie.
	 * 
	 * @param 	stock			Obiekt klasy <code>Stock</code> dodawany
	 * 							do bazy.
	 * @return	Obiekt klasy <code>Stock</code> z danymi pobranymi z
	 * 			bazy, w tym z przypisanym przez bazę identyfikatorem.
	 */
	public Stock addStock(Stock stock){
		Log.d(TAG, "Dodawanie do bazy akcji spółki "+stock);
		stmt.bindString(1, stock.getSymbol());
		stmt.bindDouble(2, stock.getMaxPrice());
		stmt.bindDouble(3, stock.getMinPrice());
		stmt.bindDouble(4, stock.getPricePaid());
		stmt.bindLong(5, stock.getQuantity());
		stmt.bindDouble(6, stock.getCurrentPrice());
		stmt.bindString(7, stock.getName());
		int id = (int) stmt.executeInsert();
		return new Stock (stock, id);
	}
	
	/**
	 * Aktualizuje cenę akcji zapisanych w 
	 * bazie.
	 * 
	 * @param 	stock			Aktualizowany obiekt klasy <code>Stock</code>.
	 */
	public void updateStockPrice(Stock stock){
		Log.d(TAG, "Aktualizowanie w bazie ceny akcji spółki "+stock.toString());
		updateStmt.bindDouble(1, stock.getCurrentPrice());
		updateStmt.bindLong(2, stock.getId());
		updateStmt.execute();
	}
	
	/**
	 * Pobieranie wszystkich akcji zapisanych w bazie.
	 * 
	 * @return	Lista wszystkich akcji zapisanych w bazie.
	 */
	public ArrayList<Stock> getStocks() {
		Log.d(TAG, "Pobieranie akcji z bazy");
		Cursor results = db.rawQuery(READ_SQL, null);
		ArrayList<Stock> stocks = new ArrayList<Stock>(results.getCount());
		if (results.moveToFirst()){
			int idCol = results.getColumnIndex(ID);
			int symbolCol = results.getColumnIndex(SYMBOL);
			int maxCol = results.getColumnIndex(MAX_PRICE);
			int minCol = results.getColumnIndex(MIN_PRICE);
			int priceCol = results.getColumnIndex(PRICE_PAID);
			int quanitytCol = results.getColumnIndex(QUANTITY);
			int currentPriceCol = results.getColumnIndex(CURRENT_PRICE);
			int nameCol = results.getColumnIndex(NAME);
			do {
				Stock stock = new Stock(results.getString(symbolCol), 
						results.getDouble(priceCol), 
						results.getInt(quanitytCol), results.getInt(idCol));
				stock.setMaxPrice(results.getDouble(maxCol));
				stock.setMinPrice(results.getDouble(minCol));
				stock.setCurrentPrice(results.getDouble(currentPriceCol));
				stock.setName(results.getString(nameCol));
				Log.d(TAG, "Akcje z bazy = " + stock.toString());
				stocks.add(stock);
			} while (results.moveToNext());
		}
		if (!results.isClosed()){
			results.close();
		}
		return stocks;
	}
	
	/**
	 * Metoda zamykająca połączenie z bazą.
	 */
	public void close(){
		helper.close();
	}	
}
