/* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import oracle.jdbc.OracleResultSet;
import oracle.jdbc.pool.OracleDataSource;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.Headers;

public class DICOMService implements HttpHandler{
	private String dbName;
	private String dataModel;
	private String dicomColumn;
	private String thumbColumn;
	
	/** 
	 * Construct a DICOM service and initialize database name and data 
	 * model. The database name is the DICOM table created in Oracle 
	 * Database. The data model is the procedure called to load the 
	 * repository data model. 
	 */
	public DICOMService() {
		dbName = null;
		dataModel = null;
	}
	
	/**
	 * Get the database name. 
	 */
	public String getDbName() {
		return this.dbName;
	}
	
	/**
	 * Set the database name. 
	 */
	public void setDbName(String name) {
		this.dbName = name;
	}	
	
	/**
	 * Get the data model.
	 */ 
	public String getDataModel() {
		return this.dataModel;
	}
	
	/**
	 * Set the data model. 
	 */
	public void setDataModel(String model) {
		this.dataModel = model;
	}
	
	/**
	 * Get DICOM column name.
	 */
	public String getDicomColumn() {
		return this.dicomColumn;
	}
	
	/**
	 * Set DICOM column name.
	 */
	public void setDicomColumn(String column) {
		this.dicomColumn = column;
	}
	
	/**
	 * Get thumbnail column name.
	 */
	public String getThumbColumn() {
		return this.thumbColumn;
	}
	
	/**
	 * Set thumbnail column name.
	 */
	public void setThumbColumn(String column) {
		this.thumbColumn = column;
	}
	
	/**
	 * Load data model in the connection.
	 */
	private void setDataModel(Connection conn) throws SQLException {
		CallableStatement cs = null;
		String dataModel = getDataModel();

		if (dataModel != null) { 	
			try { 	
	    			cs = conn.prepareCall(dataModel);
		    		cs.execute();
			} catch(SQLException se) {
		    		System.out.println(
				    "[ERROR] Call ord_dicom.setDataModel");
			} finally {
		   		cs.close();
			}
	    	}
	  }

	/**
	 * Get request string from HTTP exchange. 
	 */
	private String getRequest(HttpExchange exchange) throws IOException {
		InputStream iStream= exchange.getRequestBody();
		BufferedReader iReader = new BufferedReader(
		    new InputStreamReader(iStream));
		StringBuffer buffer = new StringBuffer();
		String line = "";
	    
		try {
			while ((line = iReader.readLine()) != null)
			buffer.append(line);
		} catch (IOException e) {
			System.out.println(
			    "[ERROR] Get request from HTTP exchange");
			throw e;
		} finally {
			iReader.close();
			iStream.close();
		}
		
		return buffer.toString();
	   
	}
	
	/**
	 * Configure server, database, port, user and password and then connect
	 * to Oracle database. 
	 */
	private Connection Connect(String serverName, String dbName, int port, 
	                           String user, String password)
	                           throws SQLException {
		Connection connection = null;
		
		try {
			OracleDataSource ods = new OracleDataSource();
			ods.setDriverType("thin");
			ods.setServerName(serverName);
			ods.setDatabaseName(dbName);
			ods.setPortNumber(port);
			ods.setUser(user);
			ods.setPassword(password);
			connection = ods.getConnection();
			
			try {
				connection.setAutoCommit(false);
			} catch (SQLException e) {
				connection.close();
				throw e;
			}
		} catch (SQLException e) {
			System.out.println(
			    "[ERROR] Connect to Oracle Database");
			throw e;
		}
		
		return connection;
	}
	
	private void downloadDICOMService(String request, Connection conn, 
	                                  HttpExchange responceExchange) 
	                                  throws SQLException, IOException {
		/*
		 * Get request from HTTP exchange and generate SQL 
		 * statement accordingly.
		 */
		DICOMSqlTemplates tmps = new DICOMSqlTemplates();
		String sql = tmps.getSqlStatement("GET", request, 
		    getDbName());
			
		/* Execute the SQL statement and get DICOMs. */
		Statement stmt = conn.createStatement();
		OracleResultSet rset = (OracleResultSet)stmt.executeQuery(sql);
			
		/* 
		 * Write serialized DICOMs into output stream in HTTP
		 * response body.
		 */
		Headers responseHeaders = responceExchange.getResponseHeaders();
		responseHeaders.set("Content-Type", "text/plain");
		responceExchange.sendResponseHeaders(200, 0);
		OutputStream responseBody = responceExchange.getResponseBody();
		
		/* Serialize returned DICOMs to a stream. */
		try {
			DICOMStream stream = new DICOMStream(rset);
		   	stream.getBytes(responseBody, getDicomColumn(), 
			    getThumbColumn());   	
		} catch (IOException e) {
			System.out.println(
			    "[ERROR] Write DICOM stream to response body");
			throw e;
		} finally {
			responseBody.close();
			rset.close();
		}			    	 
	}
	
	
	/**
	 * Handle HTTP request and provide DICOM download service. Connect 
	 * Oracle Database and start DICOM download service. If the method 
	 * in the HTTP request is "Get", generate SQL statement with regards
	 * to the request. With the SQL statement, download a set of DICOM 
	 * objects from Oracle Database and serialize them into a stream. 
	 * The stream is sent back to client in HTTP protocol.
	 */
	public void handle(HttpExchange httpExchange) throws IOException {
		Connection conn;
		
		/* Get request method from HTTP exchange. */
		String requestMethod = httpExchange.getRequestMethod();	
		if (requestMethod.equalsIgnoreCase("GET")) {
			try {
				/* Set up connection with Oracle Database.
				 * Please update the default ip address, 
				 * database name, port, user and password 
				 * with your own Oracle Database connection.				 				 				 			 
				 */				 
				conn = Connect(
				    "localhost",	// IP address
				    "orcl",		// Database name
				    1521,		// Port
				    "hr",		// User
				    "hr");		// Password
				
				/* Set data model and database name for the 
				 * connection. 
				 */
				setDataModel(conn);
			
				try {
					//String request = getRequest(
					//  httpExchange);
					String request = "All";
					downloadDICOMService(request, conn,
					    httpExchange);
					System.out.println("[LOG] DONE");
				} catch (SQLException e) {
					throw e;
				} catch (IOException e) {
					throw e;
				} finally{
					conn.close();
				}		
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
