/**************************************************************************************
 * Copyright (C) 2006-2015 EsperTech Inc. All rights reserved.                        *
 * http://www.espertech.com/esper                                                          *
 * http://www.espertech.com                                                           *
 * ---------------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the GPL license       *
 * a copy of which has been included with this distribution in the license.txt file.  *
 **************************************************************************************/
package com.espertech.esper.epl.join.plan;

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

public class QueryPlanIndexUniqueHelper
{
    public static ReducedHashKeys reduceToUniqueIfPossible(String[] hashPropsProvided, Class[] hashCoercionTypes, List<QueryGraphValueEntryHashKeyed> hashFunctions, String[][] hashPropsRequiredPerIndex) {
        if (hashPropsRequiredPerIndex == null || hashPropsRequiredPerIndex.length == 0) {
            return null;
        }
        for (String[] hashPropsRequired : hashPropsRequiredPerIndex) {
            int[] indexes = checkSufficientGetAssignment(hashPropsRequired, hashPropsProvided);
            if (indexes != null) {
                String[] props = new String[indexes.length];
                Class[] types = new Class[indexes.length];
                List<QueryGraphValueEntryHashKeyed> functions = new ArrayList<QueryGraphValueEntryHashKeyed>();
                for (int i = 0; i < indexes.length; i++) {
                    props[i] = hashPropsProvided[indexes[i]];
                    types[i] = hashCoercionTypes == null ? null : hashCoercionTypes[indexes[i]];
                    functions.add(hashFunctions.get(indexes[i]));
                }
                return new ReducedHashKeys(props, types, functions);
            }
        }
        return null;
    }

    public static int[] checkSufficientGetAssignment(String[] hashPropsRequired, String[] hashPropsProvided) {
        if (hashPropsProvided == null || hashPropsRequired == null || hashPropsProvided.length < hashPropsRequired.length) {
            return null;
        }
        // first pass: determine if possible
        for (String required : hashPropsRequired) {
            boolean found = false;
            for (String provided : hashPropsProvided) {
                if (provided.equals(required)) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                return null;
            }
        }

        // second pass: determine assignments
        int[] indexes = new int[hashPropsRequired.length];
        for (int i = 0; i < indexes.length; i++) {
            int foundIndex = -1;
            String required = hashPropsRequired[i];
            for (int j = 0; j < hashPropsProvided.length; j++) {
                if (hashPropsProvided[j].equals(required)) {
                    foundIndex = j;
                    break;
                }
            }
            indexes[i] = foundIndex;
        }
        return indexes;
    }

    public static class ReducedHashKeys {
        private final String[] propertyNames;
        private final Class[] coercionTypes;
        private final List<QueryGraphValueEntryHashKeyed> hashKeyFunctions;

        private ReducedHashKeys(String[] propertyNames, Class[] coercionTypes, List<QueryGraphValueEntryHashKeyed> hashKeyFunctions) {
            this.propertyNames = propertyNames;
            this.coercionTypes = coercionTypes;
            this.hashKeyFunctions = hashKeyFunctions;
        }

        public String[] getPropertyNames() {
            return propertyNames;
        }

        public Class[] getCoercionTypes() {
            return coercionTypes;
        }

        public List<QueryGraphValueEntryHashKeyed> getHashKeyFunctions() {
            return hashKeyFunctions;
        }
    }
}
