/*
        This software is distributed under the "New BSD License" agreement:

        Copyright (c) 2016 Bogdan-Florin Gheran, Gabriel Cramariuc, Ionela Rusu, Elena-Gina Craciun. All rights reserved.

        Redistribution and use in source and binary forms, with or without modification, are permitted provided
        that the following conditions are met:
        - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
        - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
        other materials provided with the distribution.
        - Neither the name of the University Stefan cel Mare of Suceava nor the names of its contributors may be used to endorse
        or promote products derived from this software without specific prior written permission.

        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
        ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
        THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bogdan-Florin Gheran, Gabriel Cramariuc, Ionela Rusu, or Elena-Gina Craciun
        BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
        OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        SUCH DAMAGE.
 */
package com.example.circle.tapexperiment;

import android.graphics.Point;
import android.graphics.Rect;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

//
// Implements an experiment design with multiple touch targets.
//
public class Experiment {

    private List<Target> trials = null;     // the list of all trials in the experiment, one trial = one target
    private int indexCurrentTrial;          // the current trial; indexes the trials array
    private int numRepetitionsLeft;         // how many repetitions are allowed for the current trial, decreases to zero on each attempt failure

    public Experiment() {
        trials = new ArrayList<Target>();
        indexCurrentTrial = -1;
        numRepetitionsLeft = 0;
    }

    //region [experiment logic]

    public void goToFirstTrial() {
        indexCurrentTrial = 0;
        numRepetitionsLeft = 3;
    }

    public void goToNextTrial() {
        indexCurrentTrial++;
        numRepetitionsLeft = 3;
    }

    public boolean repeatCurrentTrial() {
        numRepetitionsLeft--;
        return (numRepetitionsLeft == 0) ? false : true;
    }

    public boolean isExperimentOver() {
        return indexCurrentTrial < 0 || indexCurrentTrial >= trials.size() ? true : false;
    }

    public Target getCurrentTarget() {
        return trials.get(indexCurrentTrial);
    }

    public int getTrialsCount() {
        return trials.size();
    }

    public float getProgress() {
        return (indexCurrentTrial + 1) * 1.0f / trials.size();
    }

    //endregion

    //region [generate experiment trials]

    private Random random = new Random();
    public void generateTrials(int screenWidth, int screenHeight, float dpi) {

        // target size
        int[] TARGET_SIZES = {
                Geometry.MillimetersToPixels(1.625f, dpi),
                Geometry.MillimetersToPixels(3.25f, dpi),
                Geometry.MillimetersToPixels(5.00f, dpi),
                Geometry.MillimetersToPixels(6.75f, dpi),
                Geometry.MillimetersToPixels(8.50f, dpi),
        };

        // repetitions for each screen zone (4 edges, 4 corners, and screen center)
        int NUM_REPETITIONS_PER_CONDITION = 8;
        int[] NUM_REPETITIONS = new int[]{
                NUM_REPETITIONS_PER_CONDITION, NUM_REPETITIONS_PER_CONDITION, NUM_REPETITIONS_PER_CONDITION, NUM_REPETITIONS_PER_CONDITION,
                NUM_REPETITIONS_PER_CONDITION, NUM_REPETITIONS_PER_CONDITION, NUM_REPETITIONS_PER_CONDITION, NUM_REPETITIONS_PER_CONDITION,
                NUM_REPETITIONS_PER_CONDITION
        };

        // generate trials
        class ScreenZoneRectangle {
            public Target.Zone zoneOnScreen;
            public Rect rectangle;

            public ScreenZoneRectangle(Target.Zone zone, Rect rectangle) {
                this.zoneOnScreen = zone;
                this.rectangle = rectangle;
            }
        }

        trials = new ArrayList<Target>();
        for (int j = 0; j < TARGET_SIZES.length; j++) {

            int zoneSize = (int) (TARGET_SIZES[j] * 2.5);
            List<ScreenZoneRectangle> zones = Arrays.asList(
                    new ScreenZoneRectangle(Target.Zone.TOPLEFT, new Rect(0, 0, zoneSize, zoneSize)),
                    new ScreenZoneRectangle(Target.Zone.TOP, new Rect(screenWidth / 2 - zoneSize, 0, screenWidth / 2 + zoneSize, zoneSize)),
                    new ScreenZoneRectangle(Target.Zone.TOPRIGHT, new Rect(screenWidth - zoneSize, 0, screenWidth, zoneSize)),
                    new ScreenZoneRectangle(Target.Zone.RIGHT, new Rect(screenWidth - zoneSize, screenHeight / 2 - zoneSize * 2, screenWidth, screenHeight / 2 + zoneSize * 2)),
                    new ScreenZoneRectangle(Target.Zone.BOTTOMRIGHT, new Rect(screenWidth - zoneSize, screenHeight - zoneSize, screenWidth, screenHeight)),
                    new ScreenZoneRectangle(Target.Zone.BOTTOM, new Rect(screenWidth / 2 - zoneSize, screenHeight - zoneSize, screenWidth / 2 + zoneSize, screenHeight)),
                    new ScreenZoneRectangle(Target.Zone.BOTTOMLEFT, new Rect(0, screenHeight - zoneSize, zoneSize, screenHeight)),
                    new ScreenZoneRectangle(Target.Zone.LEFT, new Rect(0, screenHeight / 2 - zoneSize * 2, zoneSize, screenHeight / 2 + zoneSize * 2)),
                    new ScreenZoneRectangle(Target.Zone.CENTER, new Rect(screenWidth / 3, screenHeight / 4, screenWidth * 2 / 3, screenHeight * 3 / 4))
            );

            for (int indexZone = 0; indexZone < zones.size(); indexZone++) {
                ScreenZoneRectangle zone = zones.get(indexZone);
                for (int indexRepetition = 0; indexRepetition < NUM_REPETITIONS[indexZone]; indexRepetition++)
                    trials.add(
                            new Target(
                                    trials.size() + 1,
                                    new Point(
                                            zone.rectangle.left + TARGET_SIZES[j] + random.nextInt(zone.rectangle.width() - 2 * TARGET_SIZES[j]),
                                            zone.rectangle.top + TARGET_SIZES[j] + random.nextInt(zone.rectangle.height() - 2 * TARGET_SIZES[j])
                                    ),
                                    TARGET_SIZES[j],
                                    zone.zoneOnScreen
                            )
                    );
            }
        }

        // randomize the order of trials
        for (int i = 0; i < 10000; i++) {
            int index1 = random.nextInt(trials.size());
            int index2 = random.nextInt(trials.size());
            if (index1 != index2) {
                Target temp = trials.get(index1);
                trials.set(index1, trials.get(index2));
                trials.set(index2, temp);
            }
        }
    }

    //endregion
}
