/**_____________________________________________________________________________
 *
 *                                 OATS - INAF
 *  Osservatorio Astronomico di Tireste - Istituto Nazionale di Astrofisica
 *  Astronomical Observatory of Trieste - National Institute for Astrophysics
 * ____________________________________________________________________________
 *
 * Copyright (C) 20016  Istituto Nazionale di Astrofisica
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * _____________________________________________________________________________
 **/
package it.inaf.oats.vospacebackend.implementation;

import java.io.FileNotFoundException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
import java.sql.*;

import ca.nrc.cadc.net.TransientException;
import ca.nrc.cadc.util.RsaSignatureGenerator;
import ca.nrc.cadc.util.RsaSignatureVerifier;
import ca.nrc.cadc.uws.Job;
import ca.nrc.cadc.uws.Parameter;
import ca.nrc.cadc.vos.Protocol;
import ca.nrc.cadc.vos.VOSURI;
import ca.nrc.cadc.vos.View;
import it.inaf.oats.vospacebackend.exceptions.ExceptionMessage;
import it.inaf.oats.vospacebackend.exceptions.VOSpaceBackendException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Level;
import javax.sql.DataSource;

import java.io.UnsupportedEncodingException;    
import java.security.InvalidKeyException;
import javax.servlet.ServletContext;
import javax.xml.bind.DatatypeConverter;

import org.apache.log4j.Logger;

/**
 *
 * @author bertocco
 */
public class TransferGeneratorImpl {
    
    Logger log = Logger.getLogger(TransferGeneratorImpl.class);
    
    HashMap myResult = new <String, Object>HashMap();
    
    public List<URL> getURLs(VOSURI target, 
                      Protocol protocol, 
                      View view, 
                      Job job, 
                      List<Parameter> additionalParams)
                                    throws FileNotFoundException, TransientException {
        
        
        
        log.debug("VOSURI received: " + target.toString());
        
        List<URL> result = new ArrayList();
        
        // Get the node path, file name, vosuri
        String path = target.getPath();
        String fileName = target.getName();
        String vosuri = target.toString();              
        /*
        HashMap myMetadata;
        try {
            myMetadata = setPutRequest(unique_file_id_str, vosuri);

            if ((boolean)myMetadata.get("ifSuccessful")) {
                log.debug("File Put Request correctly set");            
            } else {
                log.debug("File Put Request NOT set, return null");
                return null;
            }
            
 
        } catch (MalformedURLException e) {
            log.debug("Error parsing target");
            return null;            
        } catch (VOSpaceBackendException ex) {
            java.util.logging.Logger.getLogger(TransferGeneratorImpl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException ex) {
            java.util.logging.Logger.getLogger(TransferGeneratorImpl.class.getName()).log(Level.SEVERE, null, ex);
        } 
        */
        
        try {
            String parametersToEncode = vosuri;
            String encodedParams = manageParametersEncoding(parametersToEncode);
            result.add(new URL("http://localhost/VOSpaceBackend/service/myResource/" + encodedParams));
        } catch (MalformedURLException e) {
            log.debug("Error parsing target");
            return null;            
        }
    
        return result;
    }
    
/*    
    public HashMap getPutRequests(String stored_f_name) 
                                  throws VOSpaceBackendException, SQLException {
        
        String myOp = "GET_PUT_REQ";
        
        String myQuery = "SELECT * FROM vosbackend.RequestedPuts " +
                "WHERE storedFileID=?";
        
        FileRecord myParams = new FileRecord("", stored_f_name, "", "");
        
        myResult = excuteQuery(myOp, myQuery, myParams);
        
        return myResult;
        
    }
    
    
    public HashMap setPutRequest(String stored_f_name, String vosuriStr) 
                                  throws VOSpaceBackendException, SQLException {
       
        String myOp = "SET_PUT_REQ";
        String myQuery = "INSERT INTO vosbackend.RequestedPuts " +
                "(storedFileID, vosuri)" +
                " VALUES (?, ?);";
        log.debug("Received params: " + stored_f_name + " " + vosuriStr );
        FileRecord myParams = new FileRecord("", stored_f_name, "", "", vosuriStr);       
        
        myResult = excuteQuery(myOp, myQuery, myParams);
        
        return myResult;
        
    }
    
    private HashMap excuteQuery(String operation, String query, FileRecord fileToStore) 
                                                throws VOSpaceBackendException, SQLException {
        PreparedStatement preparedStatementInsert = null;
       
        Connection dbConnection = null;
        
        try {
	    dbConnection = getDBConnection();
            log.debug("Database connection get");
        } catch (SQLException e) {
            log.fatal(e);
            ExceptionMessage exMsg = new ExceptionMessage();
            throw new VOSpaceBackendException(ExceptionMessage.getMessage("UNABLE_TO_GET_DB_CONNECTION"));
	}

	try {
	    dbConnection.setAutoCommit(false);
            log.debug("Autocommit set false");
	} catch (SQLException e) {
            log.fatal(e);
            ExceptionMessage exMsg = new ExceptionMessage();
            throw new VOSpaceBackendException(ExceptionMessage.getMessage("ERROR_DISABLING_DB_AUTOCOMMIT"));
	}
        
	// Starts JDBC Transaction
        PreparedStatement preparedQuery = null;
	try {
            
            HashMap fileToStoreFields = fileToStore.getFileRecord();
            ResultSet rs = null;   
            int rowCounter = 0;
            switch (operation) {
                case "GET_PUT_REQ":
                    preparedQuery = dbConnection.prepareStatement(query);
                    preparedQuery.setString(1, (String)fileToStoreFields.get("stored_file_name"));
                    preparedQuery.setString(2, (String)fileToStoreFields.get("vosuri"));
                    rs = preparedQuery.executeQuery();
                    rowCounter = 0;
                    while (rs.next()) {
                        rowCounter = rowCounter +1;
                        myResult.put("stored_file_name", rs.getString("storedFileID"));
                        myResult.put("vosuri", rs.getString("vosuri"));
                    }
                    if (rowCounter == 0) {
                        log.debug("GET_PUT_REQ: query successfully executed. File " + (String)fileToStoreFields.get("stored_file_name") + " not found");                      
                        myResult.put("ifSuccessful", false);
                    } else {
                        log.debug("GET_PUT_REQ: query successfully executed. File " + (String)fileToStoreFields.get("stored_file_name") + " found");
                        myResult.put("ifSuccessful", true);
                    }
                    break;
                case "SET_PUT_REQ":                   
                    log.debug("Going to prepare query for SET_PUT_REQ operation");
                    preparedQuery = dbConnection.prepareStatement(query);
                    log.debug("StoredFileName to set in db reqs " + (String)fileToStoreFields.get("stored_file_name"));                    
                    log.debug("vosuri to set in db reqs " + (String)fileToStoreFields.get("vosuri"));
                    preparedQuery.setString(1, (String)fileToStoreFields.get("stored_file_name"));
                    preparedQuery.setString(2, (String)fileToStoreFields.get("vosuri"));
                    log.debug("Going to execute query");
                    preparedQuery.executeUpdate();
                    log.debug("Query executed");
                    dbConnection.commit();
                    log.debug("Query committed");                    
                    myResult.put("ifSuccessful", true);
                    break;                    
                    
                default:                  
                    myResult.put("ifSuccessful", false);
                    ExceptionMessage exMsg = new ExceptionMessage();
                    log.fatal(ExceptionMessage.getMessage("DB_OPERATION_NOT_RECOGNIZED"));
                    throw new VOSpaceBackendException(ExceptionMessage.getMessage("DB_OPERATION_NOT_RECOGNIZED"));                    
                }
            
            dbConnection.setAutoCommit(true);
                        
            dbConnection.close();
            
        } catch (SQLException e) {

            log.error("SQLException exception executing SET file" + e.getMessage());
	    dbConnection.rollback();

	} finally {

            if (preparedQuery != null) {
		preparedQuery.close();
            }

            if (dbConnection != null) {
		dbConnection.close();
            }
            
	}
        
        return myResult;
       
    }   
 
    
    public Connection getDBConnection() throws SQLException {

        String url = "jdbc:mysql://localhost:3306/vosbackend";
        String username = "vosbackadmin";
        String password = "Peper0ne";

        System.out.println("Connecting database...");
    
        Connection connection;
        try {
           connection = DriverManager.getConnection(url, username, password);
          System.out.println("Database connected!");
        } catch (SQLException e) {
          throw new IllegalStateException("Cannot connect the database!", e);

        }
    
        return connection;
    
    }
    */
    
    private String manageParametersEncoding(String toBeSigned) {
        
        log.debug("toBeSignedInput  = " + toBeSigned);
                
        // Encription
        RsaSignatureGenerator signatureGen = null;
        try {
            signatureGen = new RsaSignatureGenerator();
        } catch (Exception e) {
            log.debug("Exception creating   RsaSignatureGenerator" + e.getMessage() + "##############");  
            e.printStackTrace();
        }
        
        ByteArrayInputStream bais = null;
        try {   
            bais = new ByteArrayInputStream(toBeSigned.getBytes());
        } catch (Exception e) {
            log.debug("Exception creating   ByteArrayInputStream");       
        }
        
        StringBuilder sb = new StringBuilder();
        try { 
            byte[] sig = signatureGen.sign(bais);
            sb.append(new String(DatatypeConverter.printBase64Binary(sig)));
        } catch (IOException ioe) {
            log.debug("1111111111111");
            log.debug(ioe.getMessage());
        } catch (InvalidKeyException ike) {
            log.debug("222222222222222");
            log.debug(ike.getMessage());        
        }
        
        log.debug("url encripted = " + sb.toString());
        String signature = sb.toString();
        
        // Validation
        /*
        RsaSignatureVerifier su = new RsaSignatureVerifier();
        boolean valid = false;
        try {
        valid = su.verify(new ByteArrayInputStream(toBeSigned.getBytes()),
                    DatatypeConverter.parseBase64Binary(signature));
        } catch (IOException ioe) {
            log.debug("2");
            log.debug(ioe.getMessage());
        } catch (InvalidKeyException ike) {
            log.debug("2");           
            log.debug(ike.getMessage());       
        }
        if (valid)
            log.debug("VALID");
        else
            log.debug("BUGGY WORK!");
        */
        String finalStr = toBeSigned + "|" + signature;
        log.debug("originalParams = " + finalStr); 
        log.debug("Message = " + toBeSigned);
        log.debug("Signature = " + signature);
        finalStr = DatatypeConverter.printBase64Binary(finalStr.getBytes());
        
        return finalStr;
        
    }


}
