package src.fr.impl;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

import src.fr.api.Part;
import src.fr.api.Category;
import src.fr.api.PartType;

public class PartImpl implements Part {

    protected PartType type; 
    protected int price;

    /*public PartImpl(PartType type){
        this.type = type;
    }*/

    private class Property { 
        public final Supplier<String> getter; 
        public final Consumer<String> setter; 
        public final Set<String> possibleValues; 
 
        Property(Supplier<String> getter, Consumer<String> setter, Set<String> possibleValues) { 
            this.getter = getter; 
            this.setter = setter; 
            this.possibleValues = possibleValues; 
        } 
    } 

    private Map<String, Property> properties = new HashMap<>(); 

    protected void addProperty(String name, Supplier<String> getter, Consumer<String> setter, Set<String> possibleValues) { 
        properties.put(name, new Property(getter, setter, possibleValues)); 
    }

    @Override
    public Set<String> getPropertyNames() {
        return Collections.unmodifiableSet(properties.keySet());
    }

    @Override
    public Optional<String> getProperty(String propertyName) {
        Objects.requireNonNull(propertyName); 
 
        if (properties.containsKey(propertyName)) { 
            String value = properties.get(propertyName).getter.get();
            if(value != null){
                return Optional.of(value);
            }
        } 
        return Optional.empty(); 
    }

    @Override
    public void setProperty(String propertyName, String propertyValue) {
        Objects.requireNonNull(propertyName); 
  		Objects.requireNonNull(propertyValue); 
 
  		if ((properties.containsKey(propertyName)) && (properties.get(propertyName).setter != null)) { 
   			properties.get(propertyName).setter.accept(propertyValue); 
  		} else { 
   		throw new IllegalArgumentException("bad property name or value: " + propertyName); 
  		} 
 	}

 	@Override 
 	public Set<String> getAvailablePropertyValues(String propertyName) { 
  		if (properties.containsKey(propertyName)) { 
   			return Collections.unmodifiableSet(properties.get(propertyName).possibleValues); 
  		} 
  	return Collections.emptySet(); 
 	} 

    public Category getCategory(){
        return this.type.getCategory();
    }

    
    public PartType getType(){
        return this.type;
    }

    public void setType(PartType type){
        this.type = type;
    }

    public int getPrice(){
        return this.price;
    }
}
