package cz.hsrs.db.util;

import cz.hsrs.db.pool.SQLExecutor;
import org.apache.commons.io.IOUtils;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

public class VgiUtil {

    /**
     * Method inserts new POI to database and returns Id of this new POI
     * @param titleValue String with value of Title parameter - need not be NULL
     * @param descValue String with value of Description parameter
     * @param catValue String with value of Category parameter
     * @param statValue String value of Status parameter
     * @param lonValue String with value of Longitude parameter - need not be NULL
     * @param latValue String with value of Latitude parameter - need not be NULL
     * @param timestampValue String with value of Timestamp parameter - need not be NULL
     * @param startTimeValue String value of Start Timestamp parameter 
     * @param userId String with name of user -  need not be NULL
     * @return ID of new POI as long
     * @throws SQLException Throws SQLException if an exception occurs during inserting
     */
    public static long insertPoi(String titleValue, String descValue, String catValue, String statValue, String lonValue, String latValue, String timestampValue, String startTimeValue, String userId) throws SQLException{
        StringBuilder ins = new StringBuilder();
        ins.append("SELECT poi.add_poi('").append(titleValue).append("', ");
        if(descValue.isEmpty()){
            ins.append("NULL, ");
        } else{
            ins.append("'").append(descValue).append("', ");
        }
        ins.append("'").append(catValue).append("', ");
        ins.append("'").append(timestampValue).append("', ");
        ins.append("'").append(userId).append("', ");
        ins.append("'").append(lonValue).append("', ");
        ins.append("'").append(latValue).append("', ");
        if(startTimeValue.isEmpty()){
            ins.append("NULL, ");
        } else{
            ins.append("'").append(startTimeValue).append("', ");
        }
        ins.append("'").append(statValue).append("');");
        
        ResultSet rs = SQLExecutor.getInstance().executeQuery(ins.toString());
        if(rs.next()){ 
            return rs.getLong(1);
        } else{
            throw new SQLException("An error occurs during inserting of new POI!");
        }
    }
    
    /**
     * Method inserts new image connected to existing POI
     * @param poiId Id of existing POI in database as long
     * @param image InputStream with loaded image 
     * @param fileSize size of image file in bytes as long 
     * @throws SQLException Throws SQLException if an exception occurs during inserting
     */
    public static long insertPoiImage(long poiId, InputStream image, long fileSize) throws SQLException{
        Date newDate = new Date();
        long newImageId = newDate.getTime();
        String query = "INSERT INTO poi.poi_image(image_id, image, ogc_fid) VALUES("+newImageId+", ?, "+poiId+");";
        SQLExecutor.insertStream(query, image, fileSize);
        return newImageId;
    }
    
    /**
     * Method inserts new image thumbnail connected to existing POI
     * @param image InputStream with loaded image
     * @param fileSize size of image file in bytes as long 
     * @throws SQLException Throws SQLException if an exception occurs during inserting
     */
    public static void insertPoiImageThumbnail(long imageId, InputStream image, long fileSize) throws SQLException{
        String query = "UPDATE poi.poi_image SET thumbnail = ? WHERE image_id = "+imageId+";";
        SQLExecutor.insertStream(query, image, fileSize);
    }

    public static long testInsertPoi(String titleValue, String descValue, String catValue, String lonValue, String latValue, String timestampValue, String userId) throws SQLException{
        String query = "SELECT poi.add_poi('"+titleValue+"', " +
                "'"+descValue+"', " +
                "'"+catValue+"', " +
                "'"+timestampValue+"', " +
                "'"+userId+"', " +
                ""+lonValue+", " +
                ""+latValue+");";
        ResultSet rs = SQLExecutor.getInstance().executeQuery(query);
        if(rs.next()){
            return rs.getLong(1);
        } else{
            throw new SQLException("An error occurs during inserting of new POI!");
        }
    }

    public static File testSelectImage(long imageId, String path){
        String query = "SELECT image, ogc_fid FROM poi.poi_image WHERE image_id ="+imageId+";";
        
        File selectedImage = null;
        try {
            ResultSet rs = SQLExecutor.getInstance().executeQuery(query);
            if(rs.next()){
                InputStream is = rs.getBinaryStream("image");
                selectedImage = new File(path+"/POI_"+imageId+".jpg");
                FileOutputStream fOS = new FileOutputStream(selectedImage);
                IOUtils.copy(is, fOS);
                IOUtils.closeQuietly(fOS);
            }
        } catch (SQLException | IOException e) {
            e.printStackTrace();
        }
        return selectedImage;
    }

    public static File testSelectThumbnail(long imageId, String path){
        String query = "SELECT thumbnail, ogc_fid FROM poi.poi_image WHERE image_id ="+imageId+";";
        
        File selectedImage = null;
        try {
            ResultSet rs = SQLExecutor.getInstance().executeQuery(query);
            if(rs.next()){
                InputStream is = rs.getBinaryStream("thumbnail");
                selectedImage = new File(path+"/POI_"+imageId+"_thumbnail.jpg");
                FileOutputStream fOS = new FileOutputStream(selectedImage);
                IOUtils.copy(is, fOS);
                IOUtils.closeQuietly(fOS);
            }
        } catch (SQLException | IOException e) {
            e.printStackTrace();
        }
        return selectedImage;
    }
    
    /** Method rescale given image to given width and height */
    public static BufferedImage rescale(BufferedImage masterImg, int widthDest, int heightDest){
        Image resizedImg = masterImg.getScaledInstance(widthDest, heightDest, Image.SCALE_FAST);
        BufferedImage rBimg = new BufferedImage(widthDest, heightDest, masterImg.getType());
        Graphics2D g=rBimg.createGraphics();
        g.drawImage(resizedImg, 0, 0, null);
        g.dispose();
        
        return rBimg;
    }
    
    /** Method rotated given image to given angle */
    public static BufferedImage rotate(BufferedImage masterImg, int angle){
        Dimension size = new Dimension(masterImg.getWidth(), masterImg.getHeight());
        int masterWidth = masterImg.getWidth();
        int masterHeight = masterImg.getHeight();
        
        double x = 0; //masterWidth / 2.0;
        double y = 0; //masterHeight / 2.0;
        switch (angle) {
            case 0:
                break;
            case 180:
                break;
            case 90:
            case 270:
                size = new Dimension(masterImg.getHeight(), masterImg.getWidth());
                x = (masterHeight - masterWidth) / 2.0;
                y = (masterWidth - masterHeight) / 2.0;
                break;
        }

        BufferedImage rotatedImg = new BufferedImage(size.width, size.height, masterImg.getTransparency());
        Graphics2D g2d = rotatedImg.createGraphics();
        AffineTransform at = AffineTransform.getTranslateInstance(x, y);
        at.rotate(Math.toRadians(angle), masterWidth / 2.0, masterHeight / 2.0);
        g2d.drawImage(masterImg, at, null);
        g2d.dispose();

        return rotatedImg;
    }
}