package caseStudy;

public class YarnColour extends SaveAsXML {
    // Describes the yardage and weight for a colour used in the pattern
    private SaveableField <String> colour;  // Colour name
    private SaveableField <Double> yardage; // Total length needed for this colour
    private SaveableField <Double> weight; // Yarn amount is frequently described by weight in oz or g instead of yardage
    private SaveableField <Integer> wpi;    // Wraps Per Inch, approximate (also not necessary)
    private SaveableField <Integer> weightCategory; // Using Craft Yarn Council's standardized system (0-7)
    private SaveableField <String> weightDescription; // Similar to weightCategory
    
 // XML Tags
    public static final String STARTCLASSTAG = "<YarnColour>";
    public static final String ENDCLASSTAG = "</YarnColour>";
    
    // Constructors
    public YarnColour() {
        initializeFields();
        colour.setValue("unknown");
        yardage.setValue(0.0);
        weight.setValue(0.0);
        wpi.setValue(0);
        weightCategory.setValue(-1);
        weightDescription.setValue("Novelty");
    }
    public YarnColour(YarnColour yarn) {
        initializeFields();
        colour.setValue(yarn.getColour());
        yardage.setValue(yarn.getYardage());
        weight.setValue(yarn.getWeight());
        wpi.setValue(yarn.getWPI());
        weightCategory.setValue(yarn.getWeightCat());
        weightDescription.setValue(yarn.getWeightDesc());
    }
    public YarnColour(String colour, double yardage, double weight, int wpi) {
        initializeFields();
        this.colour.setValue(colour.toLowerCase());
        this.yardage.setValue(yardage);
        this.weight.setValue(weight);
        this.wpi.setValue(wpi);
        weightCategory.setValue(getCategoryFromWPI(wpi));
        weightDescription.setValue(getDescFromCat(weightCategory.getValue()));
    }  
    public YarnColour(String colour, double yardage, double weight, int wpi, int weightCategory, String weightDescription) {
        initializeFields();
        this.colour.setValue(colour.toLowerCase());
        this.yardage.setValue(yardage);
        this.weight.setValue(weight);
        this.wpi.setValue(wpi);
        this.weightCategory.setValue(weightCategory);
        this.weightDescription.setValue(weightDescription);
    }
    public YarnColour(String xml) {
        initializeFields();
        this.load(xml);
    }
    
    // Accessors
    public String getColour() {
        return colour.getValue();
    }
    public Double getYardage() {
        return yardage.getValue();
    }
    public Double getWeight() {
        return weight.getValue();
    }
    public Integer getWPI() {
        return wpi.getValue();
    }
    public Integer getWeightCat() {
        return weightCategory.getValue();
    }
    public String getWeightDesc() {
        return weightDescription.getValue();
    }
    public String toString() {
        return "Need " + yardage.getValue() + "yds of " + weightDescription.getValue() + " weight yarn in " + colour.getValue();
    }
    public String save() {
        return STARTCLASSTAG
                + colour.save()
                + yardage.save()
                + weight.save()
                + wpi.save()
                + weightCategory.save()
                + weightDescription.save()
                + ENDCLASSTAG;
    }
    public boolean equals(YarnColour c) {
        if((colour.getValue() == c.getColour()) 
                && (yardage.getValue() == c.getYardage())
                && (weight.getValue() == c.getWeight())
                && (wpi.getValue() == c.getWPI())) {
            return true;
        }
        return false;
    }
    
    // Basic Modifiers
    public void setColour(String newColour) {
        colour.setValue(newColour.toLowerCase());
    }
    public void setYardage(double newYardage) {
        yardage.setValue(newYardage);
    }
    public void setWeight(double newWeight) {
        weight.setValue(newWeight);
    }
    public void setWPI(int newWPI) {
        wpi.setValue(newWPI);
        weightCategory.setValue(getCategoryFromWPI(wpi.getValue()));
        weightDescription.setValue(getDescFromCat(weightCategory.getValue()));
    }
    public boolean setWeightCat(int newWeightCat) {
        weightCategory.setValue(newWeightCat);
        weightDescription.setValue(getDescFromCat(weightCategory.getValue()));
        if(checkWrapsInCat(wpi.getValue(), weightCategory.getValue())) {
            return true;
        }
        else {
            wpi.setValue(0);
            return false;
        }
    }
    public void setWeightDesc(String newWeightDesc) {
        weightDescription.setValue(newWeightDesc);
        // TODO: create static list of yarn weight descriptors (enum?), map to categories
    }
    public void load(String xml) {
        colour.setValue(colour.getStringDataFromXML(xml));
        yardage.setValue(Double.parseDouble(yardage.getStringDataFromXML(xml)));
        weight.setValue(Double.parseDouble(weight.getStringDataFromXML(xml)));
        wpi.setValue(Integer.parseInt(wpi.getStringDataFromXML(xml)));
        weightCategory.setValue(Integer.parseInt(weightCategory.getStringDataFromXML(xml)));
        weightDescription.setValue(weightDescription.getStringDataFromXML(xml));
    }
    
    // Derive the weight category from the WPI based on the chart at https://www.craftyarncouncil.com/standards/how-measure-wraps-inch-wpi
    private static int getCategoryFromWPI(Integer wraps) {
        if (wraps < 1) {
            return -1;
        }
        else if (wraps < 5) {
            return 7;
        }
        else if (wraps < 7) {
            return 6;
        }
        else if (wraps < 10) {
            return 5;
        }
        else if (wraps < 13) {
            return 4;
        }
        else if (wraps < 16) {
            return 3;
        }
        else if (wraps < 19) {
            return 2;
        }
        else if (wraps < 31) {
            return 1;
        }
        else {
            return 0;
        }
    }
    // Derive the weight description from the weight category based on the chart at https://www.craftyarncouncil.com/standards/yarn-weight-system
    private static String getDescFromCat(Integer category) {
        switch(category) {
            case 0:
                return "Lace";
            case 1:
                return "Super Fine";
            case 2:
                return "Fine";
            case 3:
                return "Light";
            case 4:
                return "Medium";
            case 5:
                return "Bulky";
            case 6:
                return "Super Bulky";
            case 7:
                return "Jumbo";
            default:
                return "Novelty";
        }
    }
    // Verify that the WPI matches the given weight category
    private static boolean checkWrapsInCat(Integer wraps, Integer category) {
        switch(category) {
            case 0:
                if(wraps > 29)
                    return true;
                else
                    return false;
            case 1:
                if(wraps > 13 && wraps < 31)
                    return true;
                else
                    return false;
            case 2:
                if(wraps > 11 && wraps < 19)
                    return true;
                else
                    return false;
            case 3:
                if(wraps > 10 && wraps < 16)
                    return true;
                else
                    return false;
            case 4:
                if(wraps > 8 && wraps < 13)
                    return true;
                else
                    return false;
            case 5:
                if(wraps > 5 && wraps < 10)
                    return true;
                else
                    return false;
            case 6:
                if(wraps > 4 && wraps < 7)
                    return true;
                else
                    return false;
            case 7:
                if(wraps > 0 && wraps < 5)
                    return true;
                else
                    return false;
            default:
                return false;
        }
    }
    private void initializeFields() {
        colour = new SaveableField <String> ("colour");
        yardage = new SaveableField <Double> ("yardage");
        weight = new SaveableField <Double> ("weight");
        wpi = new SaveableField <Integer> ("wpi");
        weightCategory = new SaveableField <Integer> ("weightCategory");
        weightDescription = new SaveableField <String> ("weightDescription");
    }
}
