package math.games;

import math.utils.ArrayUtil;

public class GameMatrix {
    private final double[][] array;
    private int rows;
    private int cols;

    public GameMatrix() {
        this(2, 2);
    }

    public GameMatrix(double[][] array) {
        this.array = ArrayUtil.clone(array);
        this.rows = array.length;
        this.cols = array[0].length;
    }

    public GameMatrix(GameMatrix gameMatrix) {
        this.array = ArrayUtil.clone(gameMatrix.array);
        this.rows = this.array.length;
        this.cols = this.array[0].length;
    }

    public GameMatrix(double[] array, int cols) {
        this.array = ArrayUtil.oneToTwo(array, cols);
        this.rows = this.array.length;
        this.cols = cols;
    }

    public GameMatrix(int rows, int cols) {
        this.array = new double[rows][cols];
        this.rows = rows;
        this.cols = cols;
        setToValue(0.0);
    }

    public void setToValue(double value) {
        for (int i = 0; i < this.rows; i++) {
            for (int j = 0; j < this.cols; j++) {
                this.array[i][j] = value;
            }
        }
    }

    public double gameMin() {
        double min = Double.MAX_VALUE;
        for (int i = 0; i < this.rows; i++) {
            for (int j = 0; j < this.cols; j++) {
                min = Math.min(min, this.array[i][j]);
            }
        }
        return min;
    }

    public double gameMax() {
        double max = Double.MIN_VALUE;
        for (int i = 0; i < this.rows; i++) {
            for (int j = 0; j < this.cols; j++) {
                max = Math.max(max, this.array[i][j]);
            }
        }
        return max;
    }

    public Cell maximin() {
        double min = Double.MAX_VALUE;
        double max = Double.MIN_VALUE;
        Cell maxim = null;
        Cell[] arr = new Cell[this.rows];
        double[] arr1 = null;
        for (int i = 0; i < this.rows; i++) {
            arr1 = this.array[i];
            for (double v : arr1) {
                min = Math.min(min, v);
            }
            for (int k = 0; k < arr1.length; k++) {
                if (arr1[k] == min) {
                    arr[i] = new Cell(i, k, min);
                    min = 1000000000000000.0;
                    break;
                }
            }
        }
        for (Cell cell1 : arr) {
            max = Math.max(max, cell1.getValue());
        }
        for (Cell cell : arr) {
            if (max == cell.getValue()) {
                maxim = cell;
            }
        }
        return maxim;
    }

    public Cell minimax() {
        double min = Double.MAX_VALUE;
        double max = Double.MIN_VALUE;
        Cell minim = null;
        Cell[] arr = new Cell[this.cols];
        double[] arr1 = new double[this.rows];
        for (int i = 0; i < this.cols; i++) {
            for (int o = 0; o < this.rows; o++) {
                arr1[o] = this.array[o][i];
            }
            for (double v : arr1) {
                max = Math.max(max, v);
            }
            for (int k = 0; k < arr1.length; k++) {
                if (arr1[k] == max) {
                    arr[i] = new Cell(k, i, max);
                    max = -1000000000000000.0;
                    break;
                }
            }
        }
        for (Cell cell1 : arr) {
            min = Math.min(min, cell1.getValue());
        }
        for (Cell cell : arr) {
            if (min == cell.getValue()) {
                minim = cell;
            }
        }
        return minim;
    }

    public boolean hasSaddle() {
        Cell cell1 = this.maximin();
        Cell cell2 = this.minimax();
        return cell1.getValue() == cell2.getValue();
    }

    public Cell getSaddle() {
        if (this.hasSaddle()) {
            return this.maximin();
        }
        return null;
    }

    @SuppressWarnings("SwitchStatementWithTooFewBranches")
    public double[] getRowFreq() {
        double[] arr = new double[2];
        switch (this.rows) {
            case 2:
                if (this.cols == 2) {
                    arr[0] = Math.abs(this.array[1][0] - this.array[1][1]);
                    arr[1] = Math.abs(this.array[0][0] - this.array[0][1]);
                }
                break;
        }
        return arr;
    }

    @SuppressWarnings("SwitchStatementWithTooFewBranches")
    public double[] getColFreq() {
        double[] arr = new double[2];
        switch (this.cols) {
            case 2:
                if (this.rows == 2) {
                    arr[0] = Math.abs(this.array[0][1] - this.array[1][1]);
                    arr[1] = Math.abs(this.array[0][0] - this.array[1][0]);
                }
                break;
        }
        return arr;
    }

    public double price() {
        Cell sattle = this.getSaddle();
        double[] arr1 = null;
        double price = 0.0;
        if (sattle != null) {
            return sattle.getValue();
        } else {
            arr1 = this.getRowFreq();
            price = ((arr1[0] * this.array[0][0]) + (arr1[1] * this.array[1][0]))
                    / (arr1[0] + arr1[1]);
        }
        return price;
    }

    public boolean isColDominating(int colIndex1, int colIndex2) {
        boolean icd = true;
        for (int i = 0; i < this.rows; i++) {
            if (this.array[i][colIndex1] >= this.array[i][colIndex2]) {
            } else {
                icd = false;
                break;
            }
        }
        return icd;
    }

    public boolean isRowSubordinated(int rowIndex1, int rowIndex2) {
        boolean irs = true;
        for (int i = 0; i < this.cols; i++) {
            if (this.array[rowIndex1][i] <= this.array[rowIndex2][i]) {
            } else {
                irs = false;
                break;
            }
        }
        return irs;
    }

    // oblicza oczekiwana (srednia) wartosc wyplaty
    // payment: tablica wyplat; np. [5, 7, 3];
    // proportions: tablica czestosci (proporcji) tych wyplat [1, 3, 1], czyli
    // 1:3:1
    public static double average(double[] wyplaty, double[] proporcje) {
        double result = 0.0;
        if (wyplaty.length == proporcje.length) {
            double tempSum1 = 0.0;
            double tempSum2 = 0.0;
            for (int i = 0; i < wyplaty.length; i++) {
                tempSum1 += proporcje[i];
                tempSum2 += wyplaty[i] * proporcje[i];
            }
            result = tempSum2 / tempSum1;
        } else {
            System.out.println("tablice mają różne długości");
        }
        return result;
    }

    public static GameMatrix subgamer(double[][] gameArray, int rowIndex) {
        double[][] ar = ArrayUtil.clone(gameArray);
        ar = ArrayUtil.shortenArray(ar, rowIndex);
        return new GameMatrix(ar);
    }

    public static GameMatrix subgamec(double[][] gameArray, int colIndex) {
        double[][] ar = ArrayUtil.clone(gameArray);
        for (int i = 0; i < ar.length; i++) {
            ar[i] = ArrayUtil.shortenArray(ar[i], colIndex);
        }
        return new GameMatrix(ar);
    }

    public double[][] getArray() {
        return array;
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        this.rows = rows;
    }

    public int getCols() {
        return cols;
    }

    public void setCols(int cols) {
        this.cols = cols;
    }

}
