package edu.caltech.cs2.datastructures;

import edu.caltech.cs2.interfaces.ICollection;
import edu.caltech.cs2.interfaces.IDeque;
import edu.caltech.cs2.interfaces.IDictionary;

import java.util.Iterator;


public class MoveToFrontDictionary<K, V> implements IDictionary<K,V> {
    private Node<K, V> head;
    private int size;


    private static class Node<K,V> {
        public K key;
        public V value;
        public Node<K,V> next;


        public Node(K key, V value) {
            this.key = key;
            this.value = value;
            next = null;
        }
        public Node(K key, V value, Node<K, V> next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }


    }

    public MoveToFrontDictionary() {
        this.size = 0;

    }

    @Override
    public V remove(K key) {

        Node<K, V> currNode = head;
//        if (currNode == null){
//            return null;
//        }
        if (size == 0){
            return null;
        }

        if (currNode.key.equals(key)){
            V returnVal = currNode.value;
            head = currNode.next;
            size--;
            return returnVal;
        }


        while (currNode.next != null){
            if (currNode.next.key.equals(key)){
                V returnVal = currNode.next.value;
                currNode.next = currNode.next.next;
                size--;
                return returnVal;
            }

            currNode = currNode.next;
        }

        return null;
    }

    @Override
    public V put(K key, V value) {
        V returnVal = this.remove(key);
        size ++;
        Node<K, V> newNode = new Node(key, value, head);

        head = newNode;

        return returnVal;
    }

    @Override
    public boolean containsKey(K key) {

        return this.get(key) != null;
    }

    @Override
    public boolean containsValue(V value) {
        return this.values().contains(value);
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public ICollection<K> keys() {

        ICollection<K> keys = new LinkedDeque<>();
        Node<K, V> currNode = head;
        if (currNode == null){
            return keys;
        }

        while (currNode.next != null){
            keys.add(currNode.key);
            currNode = currNode.next;
        }
        if (currNode != null){
            keys.add(currNode.key);
        }
        return keys;
    }

    @Override
    public ICollection<V> values() {

        ICollection<V> values = new LinkedDeque<>();

        Node<K, V> currNode = head;
        if (currNode == null){
            return values;
        }
        while (currNode.next != null){
            values.add(currNode.value);
            currNode = currNode.next;
        }
        if (currNode != null){
            values.add(currNode.value);
        }
        return values;

    }

    public V get(K key) {
        V returnVal = remove(key);
        if (returnVal != null){
            size++;
            Node<K, V> newNode = new Node(key, returnVal, head);
            head = newNode;
        }

        return returnVal;

    }

    @Override
    public Iterator<K> iterator() {
        return this.keys().iterator();
    }


}
