package de.beyondsoft.ownchat.utils;

import android.app.Activity;
import android.content.Context;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.jpeg.exifRewrite.ExifRewriter;
import org.apache.sanselan.formats.tiff.TiffImageMetadata;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
import org.apache.sanselan.formats.tiff.write.TiffOutputDirectory;
import org.apache.sanselan.formats.tiff.write.TiffOutputField;
import org.apache.sanselan.formats.tiff.write.TiffOutputSet;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import de.beyondsoft.ownchat.BewoplanerApplication;

import static de.beyondsoft.ownchat.utils.Constants.LOG_FILES_DIR_NAME;
import static de.beyondsoft.ownchat.utils.Constants.TEXT_FILE_FORMAT;

public class Utils {
    public static void clearFullBackStack(AppCompatActivity appCompatActivity) {
        FragmentManager fragmentManager = appCompatActivity.getSupportFragmentManager();

        if(fragmentManager.getBackStackEntryCount() > 0) {
            FragmentManager.BackStackEntry first = fragmentManager.getBackStackEntryAt(0);
            fragmentManager.popBackStackImmediate(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
    }

    public static void hideKeyboard(Activity activity) {
        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        View view = activity.getCurrentFocus();

        if(view == null) {
            view = new View(activity);
        }

        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

    static boolean copyExifData(File sourceFile, File destFile) {
        String tempFileName = destFile.getAbsolutePath() + ".tmp";
        File tempFile = null;
        OutputStream tempStream = null;

        try {
            tempFile = new File(tempFileName);

            TiffOutputSet sourceSet = getSanselanOutputSet(sourceFile, TiffConstants.DEFAULT_TIFF_BYTE_ORDER);
            TiffOutputSet destSet = getSanselanOutputSet(destFile, sourceSet.byteOrder);

            if(sourceSet.byteOrder != destSet.byteOrder) {
                return false;
            }

            destSet.getOrCreateExifDirectory();

            List<?> sourceDirectories = sourceSet.getDirectories();
            for(int i=0; i<sourceDirectories.size(); i++) {
                TiffOutputDirectory sourceDirectory = (TiffOutputDirectory)sourceDirectories.get(i);
                TiffOutputDirectory destinationDirectory = getOrCreateExifDirectory(destSet, sourceDirectory);

                if(destinationDirectory == null) {
                    continue;
                }

                List<?> sourceFields = sourceDirectory.getFields();
                for(int j=0; j<sourceFields.size(); j++) {
                    TiffOutputField sourceField = (TiffOutputField) sourceFields.get(j);

                    destinationDirectory.removeField(sourceField.tagInfo);

                    destinationDirectory.add(sourceField);
                }
            }

            tempStream = new BufferedOutputStream(new FileOutputStream(tempFile));
            new ExifRewriter().updateExifMetadataLossless(destFile, tempStream, destSet);
            tempStream.close();

            if(destFile.delete()) {
                tempFile.renameTo(destFile);
            }

            return true;
        }
        catch(ImageReadException | ImageWriteException | IOException exception) {
            exception.printStackTrace();
        } finally {
            if(tempStream != null) {
                try {
                    tempStream.close();
                }
                catch(IOException e) {
                    e.printStackTrace();
                }
            }

            if(tempFile != null) {
                if(tempFile.exists()) {
                    tempFile.delete();
                }
            }
        }

        return false;
    }

    private static TiffOutputSet getSanselanOutputSet(File jpegImageFile, int defaultByteOrder) throws IOException, ImageReadException, ImageWriteException {
        TiffImageMetadata exif = null;
        TiffOutputSet outputSet = null;

        IImageMetadata metadata = Sanselan.getMetadata(jpegImageFile);
        JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;

        if(jpegMetadata != null) {
            exif = jpegMetadata.getExif();

            if (exif != null) {
                outputSet = exif.getOutputSet();
            }
        }

        // If JPEG file contains no EXIF metadata, create an empty set
        // of EXIF metadata. Otherwise, use existing EXIF metadata to
        // keep all other existing tags
        if (outputSet == null) {
            outputSet = new TiffOutputSet(exif==null?defaultByteOrder:exif.contents.header.byteOrder);
        }

        return outputSet;
    }

    private static TiffOutputDirectory getOrCreateExifDirectory(TiffOutputSet outputSet, TiffOutputDirectory outputDirectory) {
        TiffOutputDirectory result = outputSet.findDirectory(outputDirectory.type);

        if (result != null) {
            return result;
        }

        result = new TiffOutputDirectory(outputDirectory.type);

        try {
            outputSet.addDirectory(result);
        }
        catch (ImageWriteException e) {
            return null;
        }

        return result;
    }

    public static void makeScrollLog(String message) {
        Log.i("SCROLLING_LOG", message);
    }

    private static void makeLogEntry(String entry, String fileName) {
        try {
            entry += "\n\n";

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd", Locale.GERMAN);
            SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy_MM_dd_HH:mm:ss", Locale.GERMAN);
            Calendar calendar = Calendar.getInstance();

            Date today = calendar.getTime();

            String logDirPath = BewoplanerApplication.getAppContext().getExternalFilesDir(null) + File.separator + LOG_FILES_DIR_NAME;

            File logDir = new File(logDirPath);
            if(!logDir.exists()) {
                logDir.mkdir();
            }

            String logFileName = logDirPath + File.separator + fileName + "_" + simpleDateFormat.format(today) + TEXT_FILE_FORMAT;

            File logFile = new File(logFileName);

            if(!logFile.exists()) {
                logFile.createNewFile();
            }

            FileWriter fileWriter = new FileWriter(logFile, true);

            entry = simpleDateFormat2.format(today) + ": " + entry;

            fileWriter.append(entry);
            fileWriter.flush();
            fileWriter.close();

        } catch(IOException e) {
            BeyondSoftLog.logScrollingEvent_E("An error occurred while attempting to write the log file", e);
        }
    }

    public static void makeFirebaseLogEntry(String entry) {
        makeLogEntry(entry, Constants.FIREBASE_LOG);
    }

    public static boolean isBefore(Calendar calendar1, Calendar calendar2) {
        calendar1.set(Calendar.HOUR, 0);
        calendar1.set(Calendar.MINUTE, 0);
        calendar1.set(Calendar.SECOND, 0);
        calendar1.set(Calendar.MILLISECOND, 0);
        calendar1.set(Calendar.HOUR_OF_DAY, 0);

        calendar2.set(Calendar.HOUR, 0);
        calendar2.set(Calendar.MINUTE, 0);
        calendar2.set(Calendar.SECOND, 0);
        calendar2.set(Calendar.MILLISECOND, 0);
        calendar2.set(Calendar.HOUR_OF_DAY, 0);

        return calendar1.before(calendar2);
    }

    public static boolean isNullOrEmpty(String string) {
        return string == null || string.length() == 0;
    }
}
