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

import java.util.EnumSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author ranides
 * @todo (migration) assira (printf)
 */
public abstract class PrintParams {
    
    public enum PrintFlags {
        ALIGN_LEFT,
        ALIGN_RIGHT,
        
        UPPERCASE,
        LOWERCASE,
        
        ALTERNATE,
        SIGN_SHOW,
        SIGN_PADDING,
        
        USER_PARAMS,
    }
    
    /**
     * group(1) - index$
     * group(2) - flags
     * group(3) - width
     * group(4) - .precision
     */
    private static final Pattern CLASSIC = Pattern.compile("([0-9]+\\$)?([^1-9]+)?([1-9][0-9]*)?(\\.[1-9][0-9]*)?");
    
    private final String params;
    
    public final String params() {
        return params;
    }
    
    public abstract int index();

    public abstract Set<PrintFlags> flags();

    public abstract char padder();

    public abstract int width();

    public abstract int precision();

    PrintParams(String params) {
        this.params = params;
    }
    
    public static PrintParams make(String params, int index) {
        Matcher hit = CLASSIC.matcher(params);
        if(hit.matches()) {
            return new ClassicParams(hit, index);
        } else {
            return new UserParams(params, index);
        }
    }
    
    private static class UserParams extends PrintParams {
        
        private static final Set<PrintFlags> FLAGS = EnumSet.of(PrintFlags.USER_PARAMS);
        
        private final int index;

        public UserParams(String params, int index) {
            super(params);
            this.index = index;
        }

        @Override
        public final int index() {
            return index;
        }

        @Override
        public final Set<PrintFlags> flags() {
            return FLAGS;
        }

        @Override
        public final char padder() {
            return ' ';
        }

        @Override
        public final int width() {
            return -1;
        }

        @Override
        public final int precision() {
            return -1;
        }
        
    }
    
    private static class ClassicParams extends PrintParams {
        
        private final int index;
        private final Set<PrintFlags> flags;
        private final int width;
        private final int precision;
        private final char padder;

        ClassicParams(Matcher matcher, int index) {
            super(matcher.group(0));
            
            if( matcher.group(1)==null ) {
                this.index = index;
            } else {
                this.index = Integer.parseInt(matcher.group(1).substring(0, matcher.group(1).length()-1));
            }
            if( matcher.group(3)==null ) {
                this.width = -1;
            } else {
                this.width = Integer.parseInt(matcher.group(3));
            }
            if( matcher.group(4)==null ) {
                this.precision = -1;
            } else {
                this.precision = Integer.parseInt(matcher.group(4).substring(1));
            }
            
            this.padder = initPadd(matcher.group(2));
            
            this.flags = initFlags(matcher.group(2), EnumSet.noneOf(PrintFlags.class));
            if(!this.flags.contains(PrintFlags.ALIGN_LEFT)) {
                this.flags.add(PrintFlags.ALIGN_RIGHT);
            }
        }
        
        private static char initPadd(String value) {
            if( value==null ) {
                return ' ';
            }
            if(value.contains("0")) {
                return '0';
            }
            int user = value.indexOf("'");
            if(user>=0 && user<=value.length()-1) {
                return value.charAt(user+1);
            }
            return ' ';
        }
        
        private static Set<PrintFlags> initFlags(String value, Set<PrintFlags> target) {
            if( value==null ) {
                return target;
            }
            for(int i=0, n=value.length(); i<n; i++) {
                switch(value.charAt(i)) {
                    case '+': 
                        target.add(PrintFlags.SIGN_SHOW); 
                        break;
                    case ' ': 
                        target.add(PrintFlags.SIGN_PADDING); 
                        break;
                    case '-': 
                        target.add(PrintFlags.ALIGN_LEFT); 
                        break;
                    case '#': 
                        target.add(PrintFlags.ALTERNATE); 
                        break;
                    default:
                        // do nothing
                }
            }
            return target;
        }

        @Override
        public final int index() {
            return index;
        }

        @Override
        public final Set<PrintFlags> flags() {
            return flags;
        }

        @Override
        public final char padder() {
            return padder;
        }

        @Override
        public final int width() {
            return width;
        }

        @Override
        public final int precision() {
            return precision;
        }
        
    }
    
    
}
