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

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.ranides.assira.generic.Function;
import net.ranides.assira.generic.Serializer;
import net.ranides.assira.generic.ValueUtils;
import net.ranides.assira.math.HashHelper;
import net.ranides.assira.reflection.inspect.Resolver;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public final class ResolveScanner implements Serializable {
    
    private static final long serialVersionUID = 1L;

    public static final Pattern RE_COMPILE = Pattern.compile("\\{(.+?)\\}");
    
    private final String pattern;
    
    private final Pattern regex;
    
    private final Resolver[] resolvers;
    
    private ResolveScanner(String pattern) {
        
        final List<Resolver> list = new ArrayList<>();
        String cpattern = StringUtils.replace(pattern, RE_COMPILE, new Function<String, Matcher>() {
            @Override
            public String apply(Matcher source) {
                list.add( Resolver.compile(source.group(1)) );
                return "(.+)";
            }
        });
        this.pattern = pattern;
        this.regex = Pattern.compile(cpattern);
        this.resolvers = list.toArray(new Resolver[list.size()]);

    }
    
    public static ResolveScanner compile(String pattern) {
        return new ResolveScanner(pattern);
    }
    
    public static boolean scan(CharSequence input, String pattern, Object context) {
        return new ResolveScanner(pattern).scan(input, context);
    }
    
    public boolean scan(CharSequence input, Object context) {
        Matcher hit = regex.matcher(input);
        if(!hit.matches()) {
            return false;
        }
        for(int i=0; i<resolvers.length; i++) {
            resolvers[i].reference(context).put(hit.group(i+1));
        }
        return true;
    }
    
    public String pattern() {
        return pattern;
    }
    
    private Object writeReplace() {
        return Serializer.proxy(this, pattern);
    }

    @Override
    public int hashCode() {
        return HashHelper.hashValues(5, 89, pattern);
    }

    @Override
    public boolean equals(Object object) {
        if(object instanceof ResolveScanner) {
            return ValueUtils.equals(this.pattern, ((ResolveScanner)object).pattern);
        } else {
            return false;
        }
    }

}
