package org.opencompare.api.java;

import org.opencompare.api.java.util.DiffResult;

import java.util.*;

/**
 * Created by gbecan on 6/10/15.
 */
public class PCMMetadata {

    protected PCM pcm;
    protected Map<Product, Integer> productPositions;
    protected Map<Feature, Integer> featurePositions;

    public PCMMetadata(PCM pcm) {
        this.pcm = pcm;
        this.productPositions = new HashMap<Product, Integer>();
        this.featurePositions = new HashMap<Feature, Integer>();
    }

    public Integer getLastIndex() {
        Integer result = 0;
        for (Product product : productPositions.keySet()) {
            Integer index = getProductPosition(product);
            if (result < index) {
                result = index;
            }
        }
        return result;
    }

    /**
     * Returns the absolute position of the product
     * @param product
     * @return the absolution position of 'product' or null if it is not specified
     */
    public int getProductPosition(Product product) {
        if (!productPositions.containsKey(product)) {
            Integer index = getLastIndex() + 1;
            setProductPosition(product, index);
            return index;
        }
        return productPositions.get(product);
    }

    /**
     * Define the absolute position of the product in the PCM
     * @param product
     * @param position
     */
    public void setProductPosition(Product product, int position) {
        productPositions.put(product, position);
    }

    /**
     * Returns the absolute position of the feature
     * @param feature
     * @return the absolution position of 'feature' or null if it is not specified
     */
    public int getFeaturePosition(Feature feature) {
        if (!featurePositions.containsKey(feature)) {
            Integer index = getLastIndex() + 1;
            setFeaturePosition(feature, index);
            return index;
        }
        return featurePositions.get(feature);
    }

    /**
     * Define the absolute position of the feature in the PCM
     * @param feature
     * @param position
     */
    public void setFeaturePosition(Feature feature, int position) {
        featurePositions.put(feature, position);
    }

    public List<Product> getSortedProducts() {
        List<Product> result = new ArrayList<>();
        for (Product product : pcm.getProducts()) {
            result.add(getProductPosition(product) - 1, product);
        }
        return result;
    }

    public List<Feature> getSortedFeatures() {
        List<Feature> result = new ArrayList<>();
        for (Feature feature : pcm.getConcreteFeatures()) {
            result.add(getFeaturePosition(feature) - 1, feature);
        }
        return result;
    }

    public Boolean hasDifferences(PCMMetadata metadata) {
        if (!getSortedProducts().retainAll(metadata.getSortedProducts())) {
            return true;
        }
        if (!getSortedFeatures().retainAll(metadata.getSortedFeatures())) {
            return true;
        }
        for (Product product : productPositions.keySet()){
            for (Product metaProd : metadata.getSortedProducts()) {
                if (product.getName().equals(metaProd.getName())) {
                    if (productPositions.get(product) != metadata.getProductPosition(metaProd)) {
                        return true;
                    }
                }
            }
        }
        for (Feature feature : featurePositions.keySet()){
            for (Feature metaFeat : metadata.getSortedFeatures()) {
                if (feature.getName().equals(metaFeat.getName())) {
                    if (featurePositions.get(feature) != metadata.getFeaturePosition(metaFeat)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @Override
    public String toString() {
        String result = "PCMMetadata(";
        result += productPositions.toString() + ", ";
        result += featurePositions.toString() + ")";
        return result;
    }
}

@@ -487,32 +487,124 @@
 eger%3E();%0A    %7D%0A%0A
+    /**%0A     * Return the last product index used%0A     * @return a integer as index%0A     */%0A
     public Integ
@@ -605,32 +605,39 @@
  Integer getLast
+Product
 Index() %7B%0A      
@@ -889,24 +889,423 @@
 esult;%0A    %7D
+%0A    /**%0A     * Return the last feature index used%0A     * @return a integer as index%0A     */%0A    public Integer getLastFeatureIndex() %7B%0A        Integer result = 0;%0A        for (Feature feature : featurePositions.keySet()) %7B%0A            Integer index = getFeaturePosition(feature);%0A            if (result %3C index) %7B%0A                result = index;%0A            %7D%0A        %7D%0A        return result;%0A    %7D
 %0A%0A    /**%0A  
@@ -1345,32 +1345,56 @@
 n of the product
+ or create if not exists
 %0A     * @param p
@@ -1625,32 +1625,39 @@
  index = getLast
+Product
 Index() + 1;%0A   
@@ -2088,32 +2088,56 @@
 n of the feature
+ or create if not exists
 %0A     * @param f
@@ -2376,16 +2376,23 @@
  getLast
+Feature
 Index() 
@@ -2772,32 +2772,152 @@
 sition);%0A    %7D%0A%0A
+    /**%0A     * Return the sorted products concordingly with metadata%0A     * @return an ordered list of products%0A     */%0A
     public List%3C
@@ -2951,24 +2951,29 @@
 ) %7B%0A        
+Array
 List%3CProduct
@@ -3152,32 +3152,152 @@
  result;%0A    %7D%0A%0A
+    /**%0A     * Return the sorted features concordingly with metadata%0A     * @return an ordered list of features%0A     */%0A
     public List%3C
@@ -3335,16 +3335,21 @@
         
+Array
 List%3CFea
@@ -3544,24 +3544,180 @@
 ult;%0A    %7D%0A%0A
+    /**%0A     * Compare with an other metadata instance%0A     * @param metadata%0A     * @return false if metadata given as parameter not equal to this%0A     */%0A
     public B

Comment added and bugfix on product and feature indexes retrieval