package org.xdef.impl.parsers;

import java.net.URI;
import java.net.URISyntaxException;
import org.xdef.XDParseResult;
import static org.xdef.XDParser.BASE;
import static org.xdef.XDParser.ENUMERATION;
import static org.xdef.XDParser.LENGTH;
import static org.xdef.XDParser.MAXLENGTH;
import static org.xdef.XDParser.MINLENGTH;
import static org.xdef.XDParser.PATTERN;
import static org.xdef.XDParser.WHITESPACE;
import static org.xdef.XDParser.WS_COLLAPSE;
import org.xdef.XDValue;
import static org.xdef.XDValueID.XD_ANYURI;
import org.xdef.impl.code.DefUri;
import org.xdef.msg.XDEF;
import org.xdef.proc.XXNode;
import org.xdef.sys.SRuntimeException;

/** Parser of XML Schema (XSD) "anyURI" type.
 * @author Vaclav Trojan
 */
public class XSParseAnyURI extends XSAbstractParser {
    private static final String ROOTBASENAME = "anyURI";
    protected long _minLength;
    protected long _maxLength;
    protected DefUri[] _enumeration;

    public XSParseAnyURI() {super(); _whiteSpace = WS_COLLAPSE; _minLength = _maxLength = -1;}

    @Override
    public void initParams() {
        _patterns = null;
        _enumeration = null;
        _minLength = _maxLength = -1;
        _whiteSpace = WS_COLLAPSE;
    }
    @Override
    public int getLegalKeys() {
        return PATTERN +
            ENUMERATION +
            WHITESPACE +
//			MAXINCLUSIVE +
//			MAXEXCLUSIVE +
//			MININCLUSIVE +
//			MINEXCLUSIVE +
//			TOTALDIGITS +
//			FRACTIONDIGITS +
            LENGTH +
            MAXLENGTH +
            MINLENGTH +
//			NORMALIZE +
//			SEPARATOR +
//			ITEM +
            BASE +
            0;
    }

    @Override
    public byte getDefaultWhiteSpace() {return WS_COLLAPSE;}
    @Override
    public void parseObject(final XXNode xnode, final XDParseResult p){
        int pos0 = p.getIndex();
        p.isSpaces();
        String s = p.nextToken();
        try {
            p.setParsedValue(new DefUri(new URI(s)));
        } catch (URISyntaxException ex) {
            p.errorWithString(XDEF.XDEF809, parserName()); //Incorrect value of '&{0}'&{1}{: }
            return;
        }
        p.isSpaces();
        p.replaceParsedBufferFrom(pos0, s);
        checkPatterns(p);
        checkLength(p);
        checkEnumeration(p);
    }
    @Override
    public void setLength(final long x) { _minLength = _maxLength = x; }
    @Override
    public long getLength() {return _minLength == _maxLength ? _minLength: -1;}
    @Override
    public void setMaxLength(final long x) { _maxLength = x; }
    @Override
    public long getMaxLength() { return _maxLength; }
    @Override
    public void setMinLength(final long x) { _minLength = x; }
    @Override
    public long getMinLength() { return _minLength; }
    @Override
    public XDValue[] getEnumeration() {return _enumeration;}
    @Override
    public void setParseSQParams(final Object... params) {
        if (params != null && params.length >= 1) {
            Object par1 = params[0];
            _minLength = Integer.parseInt(par1.toString());
            switch (params.length) {
                case 1: _maxLength = _minLength; break;
                case 2: _maxLength = Integer.parseInt(params[1].toString()); break;
                default: throw new SRuntimeException("Incorrect number of parameters");
            }
        }
    }
    @Override
    public void setEnumeration(final Object[] o) {
        _enumeration = null;
        if (o == null || o.length == 0) {
            return;
        }
        DefUri[] e = null;
        //the list of strings must be sorted by length down
    loop:
        for (Object o1 : o) {
            DefUri x = (DefUri) iObject(null, o1);
            if (e == null) {
                e = new DefUri[]{x};
            } else {
                for (DefUri e1 : e) {
                    if (e1.equals(x)) {
                        //already is in enumeration
                        continue loop;
                    }
                }
                DefUri[] old = e;
                e = new DefUri[old.length + 1];
                System.arraycopy(old, 0, e, 0, old.length);
                e[old.length] = x;
            }
        }
        _enumeration = e;
    }
    @Override
    public short parsedType() {return XD_ANYURI;}
    @Override
    public String parserName() {return ROOTBASENAME;}

    void checkLength(final XDParseResult p) {
        if (p.matches()) {
            String s = p.getParsedValue().toString();
            int len = s.length();
            if (_minLength != -1 && len < _minLength) {
                //Length of value of '&{0}' is too short"&{0}'&{1}
                p.errorWithString(XDEF.XDEF814, parserName());
            } else if (_maxLength != -1 && len > _maxLength) {
                p.errorWithString(XDEF.XDEF815, parserName());//Length of value of '&{0}' is too long&{0}'{: }
            }
        }
    }
}