/*
// Licensed to Julian Hyde under one or more contributor license
// agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership.
//
// Julian Hyde licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
package org.olap4j.mdx.parser.impl;

import org.olap4j.impl.Olap4jUtil;
import org.olap4j.mdx.ParseRegion;
import org.olap4j.mdx.ParseTreeNode;
import org.olap4j.mdx.SelectNode;
import org.olap4j.mdx.parser.MdxParseException;
import org.olap4j.mdx.parser.MdxParser;

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

/**
 * Default implementation of {@link org.olap4j.mdx.parser.MdxParser MDX Parser}.
 *
 * @author jhyde
 * @since Aug 22, 2006
 */
public class DefaultMdxParserImpl implements MdxParser {
    private boolean debug = false;
    private final FunTable funTable = new FunTable() {
        public boolean isProperty(String s) {
            return s.equalsIgnoreCase("CHILDREN");
        }
    };

    /**
     * Creates a DefaultMdxParserImpl.
     */
    public DefaultMdxParserImpl() {
        super();
    }

    public SelectNode parseSelect(String mdx) {
        try {
            return new MdxParserImpl(mdx, debug, funTable, false)
                .selectStatement();
        } catch (TokenMgrError e) {
            throw convertException(mdx, e);
        } catch (ParseException e) {
            throw convertException(mdx, e);
        }
    }

    public ParseTreeNode parseExpression(String mdx) {
        try {
            return new MdxParserImpl(mdx, debug, funTable, false).expression();
        } catch (TokenMgrError e) {
            throw convertException(mdx, e);
        } catch (ParseException e) {
            throw convertException(mdx, e);
        }
    }

    /**
     * Converts the exception so that it looks like the exception produced by   
     * JavaCUP. (Not that that format is ideal, but it minimizes test output    
     * changes during the transition from JavaCUP to JavaCC.)                   
     *
     * @param queryString MDX query string                                      
     * @param pe JavaCC parse exception                                         
     * @return Wrapped exception                                                
     */
    private RuntimeException convertException(
        String queryString,
        Throwable pe)
    {
        ParseRegion parseRegion = null;
        String message = null;
        if (pe instanceof TokenMgrError) {
            Pattern pattern =
                Pattern.compile(
                    "Lexical error at line ([0-9]+), column ([0-9]+)\\. .*");
            final Matcher matcher = pattern.matcher(pe.getMessage());
            if (matcher.matches()) {
                Olap4jUtil.discard(matcher);
                int line = Integer.parseInt(matcher.group(1));
                int column = Integer.parseInt(matcher.group(2));
                parseRegion = new ParseRegion(line, column);
                message = pe.getMessage();
            }
        } else if (pe instanceof ParseException
            && pe.getMessage().startsWith("Encountered "))
        {
            Token errorToken = ((ParseException) pe).currentToken.next;
            parseRegion =
                new ParseRegion(
                    errorToken.beginLine,
                    errorToken.beginColumn,
                    errorToken.endLine,
                    errorToken.endColumn);
            message = "Syntax error at line "
                + parseRegion.getStartLine()
                + ", column "
                + parseRegion.getStartColumn()
                + ", token '"
                + errorToken.image
                + "'";
        }
        Throwable e;
        if (parseRegion != null) {
            e = new MdxParseException(
                parseRegion,
                message);
        } else {
            e = pe;
        }
        throw new RuntimeException(
            "Error while parsing MDX statement '" + queryString + "'",
            e);
    }

    interface FunTable {
        boolean isProperty(String s);
    }
}

// End DefaultMdxParserImpl.java
