/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.text.format;

import java.awt.Color;
import java.awt.Font;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import net.ranides.assira.generic.CompareUtils;
import net.ranides.assira.generic.HashUtils;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
  */
public final class AnsiScheme implements Serializable {
    
    private static final long serialVersionUID = 0x401L;
    
    public static final AnsiScheme DEFAULT = new AnsiScheme();
    
    private final Map<Integer, Color> colors;
    
    private final Map<Integer, Font> fonts;
    
    public AnsiScheme() {
        colors = new HashMap<>();
        fonts = new HashMap<>();
    }
    
    public AnsiScheme(AnsiScheme scheme) {
        colors = new HashMap<>(scheme.colors);
        fonts = new HashMap<>(scheme.fonts);
    }

    public Collection<Color> colors() {
        return colors.values();
    }
    
    public Collection<Font> fonts() {
        return fonts.values();
    }
    
    public Color getColor(int index) {
        return colors.containsKey(index) ? colors.get(index) : null;
    }
    
    public Font getFont(int index) {
        return fonts.containsKey(index) ? fonts.get(index) : null;
    }
    
    public void setColor(int index, Color color) {
        if(0 == index) {
            throw new IllegalArgumentException("default entry is immutable");
        }
        colors.put(index, color);
    }
    
    public void setFont(int index, Font font) {
        if(0 == index) {
            throw new IllegalArgumentException("default entry is immutable");
        }
        fonts.put(index, font);
    }
    
    public int addColor(Color color) {
        int i = colors.size() + 1;
        while(colors.containsKey(i)) {
            i++;
        }
        colors.put(i, color);
        return i;
    }
    
    public int addFont(Font font) {
        int i = fonts.size() + 1;
        while(fonts.containsKey(i)) {
            i++;
        }
        fonts.put(i, font);
        return i;
    }
    
    public AnsiSchemeAttr addAttr(Color back, Color fore, Font font, int flags) {
        return new AnsiSchemeAttr(addColor(back), addColor(fore), addFont(font), flags);
    }
    
    public AnsiSchemeAttr compute(AnsiAttr value) {
        return new AnsiSchemeAttr(value.getBack(), value.getFore(), value.getFont(), value.getFlags());
    }

    @Override
    public int hashCode() {
        return HashUtils.hashValues(7, 83, colors, fonts);
    }

    @Override
    public boolean equals(Object object) {
        if(!(object instanceof AnsiScheme)) {
            return false;
        }
        AnsiScheme value = (AnsiScheme)object;
        return 
            CompareUtils.equals(colors, value.colors) &&
            CompareUtils.equals(fonts, value.fonts);
    }
    
    
    
    public class AnsiSchemeAttr extends AnsiAttr.Mutable {
        
        private static final long serialVersionUID = 4L;
        
        public AnsiSchemeAttr(int back, int fore, int font, int flags) {
            this.back = back;
            this.fore = fore;
            this.font = font;
            this.flags = flags;
        }
        
        @Override
        public Color getComputedFore() {
            return AnsiScheme.this.getColor(fore);
        }

        @Override
        public Color getComputedBack() {
            return AnsiScheme.this.getColor(back);
        }

        @Override
        public Font getComputedFont() {
            return AnsiScheme.this.getFont(font);
        }
        
        public void setFont(Font value) {
            AnsiScheme.this.setFont(font, value);
        }
        
        public void setFore(Color value) {
            AnsiScheme.this.setColor(fore, value);
        }
        
        public void setBack(Color value) {
            AnsiScheme.this.setColor(back, value);
        }
        
        public void setFlags(int value) {
            this.flags = value;
        }

    }
    
}
