/*
 * $URL$
 * $Revision$
 * $LastChangedBy$
 * $LastChangedDate$
 *
 * Copyright (c) 2005 syseca AG, Switzerland
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of syseca AG. ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you
 * entered into with syseca AG.
 */
package ch.spherIC.resultlist;

import android.app.Activity;

import android.content.Context;

import android.content.res.Resources;

import android.graphics.Bitmap;

import android.graphics.Bitmap.Config;

import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import android.graphics.Paint.Style;

import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;

import android.util.DisplayMetrics;

import ch.spherIC.EVFormula;
import ch.spherIC.EasyBracketMain;
import ch.spherIC.R;

import java.text.DecimalFormat;

import java.util.ArrayList;
import java.util.List;


/**
 * Factory that creates the exposure icons according to the EV range and values.
 */
public class ExposureFactory {

    public static final DecimalFormat evDF = new DecimalFormat("0.######");

    /**
     * DOCUMENT ME!
     *
     * @param   context          DOCUMENT ME!
     * @param   dpEV             DOCUMENT ME!
     * @param   bpEv             DOCUMENT ME!
     * @param   calcPrmAperture  DOCUMENT ME!
     * @param   calcPrmEvStep    DOCUMENT ME!
     * @param   fixBP            DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     */
    public static List<Exposure> calculateExposures(Context context, double dpEV, double bpEv, double calcPrmAperture,
                                                    double calcPrmEvStep, boolean fixBP, List<Double> allowedShutters) {
        Exposure exp;
        List<Exposure> exposures = new ArrayList<Exposure>();
        double deltaEV = bpEv - dpEV;
        long nbrExposures = Math.round(deltaEV / calcPrmEvStep) + 1;

        // correct the deltaEV
        deltaEV = calcPrmEvStep * (nbrExposures - 1);

        double baseEVStep = -deltaEV / 2;

        for (int i = 0; i < nbrExposures; i++) {

            boolean found = false;
            String shutterSpeed = "";
            double shutter;
            double evValue = 0;
            double evStep = baseEVStep + i * calcPrmEvStep;

            if (fixBP) {
                evValue = bpEv - (nbrExposures - 1 - i) * calcPrmEvStep;
            } else {
                evValue = dpEV + i * calcPrmEvStep;
            }

            shutter = Double.valueOf(evDF.format((EVFormula.calcShutterSpeed(calcPrmAperture, evValue))));

            for (int j = 1; j < allowedShutters.size(); j++) {
                double v1 = allowedShutters.get(j - 1);
                double v2 = allowedShutters.get(j);

                if ((v1 <= shutter && shutter <= v2) || (v2 <= shutter && shutter <= v1)) {

                    if (Math.abs(shutter - v1) <= Math.abs(shutter - v2)) {
                        shutterSpeed = (v1 < 1) ? "1/" + evDF.format((1 / v1)) : "" + EasyBracketMain.DF.format(v1) + "''";
                    } else {
                        shutterSpeed = (v2 < 1) ? "1/" + evDF.format((1 / v2)) : "" + EasyBracketMain.DF.format(v2) + "''";
                    }
                    found = true;
                    break;
                }
            }

            if (!found) {
                shutterSpeed = (shutter < 1) ? "1/" + Math.round(1 / shutter) : "" + EasyBracketMain.DF.format(shutter) + "''";
            }

            exp = new Exposure(i + 1, "f/" + EasyBracketMain.DF.format(calcPrmAperture), shutterSpeed, evStep, deltaEV,
                               getExpIcon(context, i + 1, (int) nbrExposures));
            exposures.add(exp);
        }

        return exposures;
    }


    /**
     * Retrieves Icon.
     *
     * @param   context  Context
     * @param   exp {@link Exposure} object
     *
     * @return  Color stepped icon
     */
    private static Bitmap getExpIcon(Context context, int expNbr, int nbrExposures) {

        Bitmap mIcon;
        Bitmap mIconBG;
        Bitmap mIconSymbol;
        Bitmap mIconSymbol_bl;
        Canvas canvas;
        Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        final Resources res = context.getResources();
        final int twentyPercentGray = Math.round(255f * 0.8f);
        int deltaRGB = twentyPercentGray;
        int iSize;
        int iSize_r;
        int iStart;

        DisplayMetrics metrics = new DisplayMetrics();
        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);

        switch (metrics.densityDpi) {

        case DisplayMetrics.DENSITY_LOW:
            iSize = 18;
            iSize_r = 17;
            iStart = 1;
            break;

        case DisplayMetrics.DENSITY_MEDIUM:
            iSize = 24;
            iSize_r = 22;
            iStart = 2;
            break;

        case DisplayMetrics.DENSITY_HIGH:
            iSize = 36;
            iSize_r = 33;
            iStart = 2;
            break;

        default:
            iSize = 72;
            iSize_r = 68;
            iStart = 2;
            break;
        }


        if (expNbr > 1 || nbrExposures > 1) {
            deltaRGB = twentyPercentGray / (nbrExposures - 1) * (expNbr - 1);
        }

        // The background
        mIconBG = Bitmap.createBitmap(iSize, iSize, Config.ARGB_8888);
        mIconBG.eraseColor(0x00000000);
        canvas = new Canvas(mIconBG);
        mPaint.setStyle(Style.FILL);
        mPaint.setColor(Color.argb(255, deltaRGB, deltaRGB, deltaRGB));
        canvas.drawRect(iStart, iStart, iSize_r, iSize_r, mPaint);

        // Let's retrieve all icon pieces as Bitmaps.
        mIcon = BitmapFactory.decodeResource(res, R.drawable.exposureicon_frame);
        mIconSymbol = BitmapFactory.decodeResource(res, R.drawable.exposureicon_symb_white);
        mIconSymbol_bl = BitmapFactory.decodeResource(res, R.drawable.exposureicon_symb_black);

        // Prepares the paint that will be used to draw our icon mask. Using
        // PorterDuff.Mode.SRC_OVER means the image that will be drawn will
        // mask the already drawn image.
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));

        // We're now ready to drawn our Android-like icon :)
        if (deltaRGB > twentyPercentGray / 2) {
            canvas.drawBitmap(mIconSymbol_bl, 0, 0, mPaint);
        } else {
            canvas.drawBitmap(mIconSymbol, 0, 0, mPaint);
        }
        canvas.drawBitmap(mIcon, 0, 0, mPaint);

        return mIconBG;
    }
}
