package jp.ac.osaka_u.ist.sel.similarity.register.database;

//import java.io.File;
//import java.io.IOException;
import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//import java.util.regex.Pattern;

import jp.ac.osaka_u.ist.sel.similarity.database.AbstractDAO;
import jp.ac.osaka_u.ist.sel.similarity.database.ColumnName;
import jp.ac.osaka_u.ist.sel.similarity.database.SQLGenerator;
import jp.ac.osaka_u.ist.sel.similarity.database.TableType;
import jp.ac.osaka_u.ist.sel.similarity.database.TransactionManager;

/**
 * DAO class for information of files.
 * 
 * @author ysk-ssk
 *
 */
/**
 * @author Ares
 *
 */
public class InsertionFileDAO extends AbstractDAO {
	private int _maxId = 1;
	private Map<FileInfo,Integer> _fileToIdMapping = new HashMap<FileInfo,Integer>();
	// heap size: (2 byte * String.MAX_LENGTH + 32 bit) * n

	public InsertionFileDAO(TransactionManager transactionManager)
			throws SQLException {
		super(transactionManager);
		initializeNameToIdMapping();
	}
	
	/**
	 * Caching file IDs.
	 * 
	 * @throws SQLException
	 */
	private void initializeNameToIdMapping() throws SQLException {
		// create sql
		ColumnName[] columns = {ColumnName.ID,ColumnName.PATH,ColumnName.DOMAIN_ID};
		String sql = SQLGenerator.getSelectStatement(TableType.FILE_INFO, columns);
		// prepare the statement
		PreparedStatement pstmt = prepareStatement(sql);
		// execute
		ResultSet results = executeQuery(pstmt);
		while (results.next()) {
			FileInfo fileInfo = new FileInfo(results.getString(2),results.getInt(3));
			_fileToIdMapping.put(fileInfo,results.getInt(1));
		}
		_maxId = getMaxId();
		if (_maxId != -1) {
			_maxId += 1;
		} else {
			_maxId = 1;
		}
	}
	
	private int getMaxId() throws SQLException {
		String sql = SQLGenerator.getSelectMaxStatement(TableType.FILE_INFO, ColumnName.ID);
		return getIntegerValue(executeQuery(prepareStatement(sql))); 
	}
	
	/**
	 * Insert following information about files:
	 * 
	 * * file path
     * * file extension
     * * file size
	 * * domain ID (foreign key)
	 * 
	 * @param filePath
     * @param ext
	 * @param fileSize
     * @param domainId
	 * @return
	 * @throws SQLException
	 */
	public boolean insert(String filePath, String ext, long fileSize, int domainId) throws SQLException {
	    // avoid duplicated register
		Set<FileInfo> fileInfoSet = _fileToIdMapping.keySet();
		FileInfo fileInfo = new FileInfo(filePath,domainId);
		if (fileInfoSet != null) {
			if (fileInfoSet.contains(fileInfo)) {
				return true;
			}
		}
		PreparedStatement pstmt = null;
		// create sql
		String sql = "insert into " + TableType.FILE_INFO + " values (?,?,?,?,?)";
		// prepare the statement
		pstmt = prepareStatement(sql);
		pstmt.setInt(1, _maxId);
		pstmt.setString(2, filePath);
        pstmt.setString(3, ext);
		pstmt.setLong(4, fileSize);
		pstmt.setInt(5, domainId);
		// execute query
		if (executeUpdate(pstmt) == 1) {
			_fileToIdMapping.put(fileInfo, _maxId++);
			return true;
		}
		return false;
	}
	
	/**
	 * This method returns the file relative path from rootPath.
	 * 
	 * @param rootPath
	 * @param file
	 * @return
	 * @throws IOException 
	 * @throws IOException
	 *
	public static String getRelativePath(String rootPath, File file) throws IOException {
		String path = getName(file);
		Pattern rootPattern = Pattern.compile('^' + Pattern.quote(rootPath));
		if (rootPattern.matcher(path).find()) {
	        path = rootPattern.matcher(path).replaceFirst("");
	        return path;
		}
		return null;
	}*/
    public static String getPath(File file) {
        return file.getPath();
    }
    
	private class FileInfo {
		private final String _name;
		private final int _domainId;
		
		public FileInfo(String path, int domainId) {
			_name = path;
			_domainId = domainId;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result + _domainId;
			result = prime * result + ((_name == null) ? 0 : _name.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			FileInfo other = (FileInfo) obj;
			if (!getOuterType().equals(other.getOuterType()))
				return false;
			if (_domainId != other._domainId)
				return false;
			if (_name == null) {
				if (other._name != null)
					return false;
			} else if (!_name.equals(other._name))
				return false;
			return true;
		}

		private InsertionFileDAO getOuterType() {
			return InsertionFileDAO.this;
		}
		
	}
}
