package org.apache.maven.scm.provider.hg;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 */

import org.apache.maven.scm.ScmException;
import org.apache.maven.scm.ScmFileStatus;
import org.apache.maven.scm.log.DefaultLog;
import org.apache.maven.scm.provider.hg.command.HgCommandConstants;
import org.apache.maven.scm.provider.hg.command.HgConsumer;
import org.codehaus.plexus.util.cli.Commandline;

import java.io.File;

/**
 * Check hg installation.
 *
 * @author <a href="mailto:thurner.rupert@ymono.net">thurner rupert</a>
 * @author <a href="mailto:ryan@darksleep.com">ryan daum</a>
 *
 */
public class HgConfig
{
    //Minimum version for the Hg SCM
    private static final String HG_REQ = "0.9.2";

    // The string which indicates the beginning of the Mercurial line
    private static final String HG_VERSION_TAG = "Mercurial Distributed SCM (version ";

    // URL to download mercurial from
    private static final String HG_INSTALL_URL = "'http://www.selenic.com/mercurial/wiki/index.cgi/Download'";

    //Configuration to check with default values (not installed)
    private HgVersionConsumer hgVersion = new HgVersionConsumer( null );

    HgConfig( File workingDir )
    {
        try
        {
            hgVersion = getHgVersion( workingDir );
        }
        catch ( ScmException e )
        {
            //Ignore -  is not installed.
            //This is already recorded thus we do not generate more info.
        }

    }

    /**
     * @return True if one can run basic hg commands
     */
    private boolean isInstalled()
    {
        return hgVersion.isVersionOk( HG_REQ );
    }

    /**
     * @return True if all modules for hg are installed.
     */
    private boolean isComplete()
    {
        return isInstalled();
    }

    // Consumer to find the Mercurial version
    public static HgVersionConsumer getHgVersion( File workingDir )
        throws ScmException
    {
        String[] versionCmd = new String[]{ HgCommandConstants.VERSION };
        HgVersionConsumer consumer = new HgVersionConsumer( HG_VERSION_TAG );
        Commandline cmd = HgUtils.buildCmd( workingDir, versionCmd );

        // Execute command
        HgUtils.executeCmd( consumer, cmd );

        // Return result
        return consumer;
    }


    /**
     * Iterate through two dot-notation version strings, normalize them to the same length, then
     * do alphabetic comparison
     *
     * @param version1
     * @param version2
     * @return true if version2 is greater than version1
     */
    private static boolean compareVersion( String version1, String version2 )
    {
        int l1, l2;
        String v1, v2;

        v1 = version1;
        v2 = version2;
        l1 = version1.length();
        l2 = version2.length();

        if ( l1 > l2 )
        {
            for ( int x = l2; x >= l1; x-- )
            {
                v2 += ' ';
            }
        }
        if ( l2 > l1 )
        {
            for ( int x = l1; x <= l2; x++ )
            {
                v1 += ' ';
            }
        }

        return v2.compareTo( v1 ) >= 0;
    }


    /**
     * Get version of the executable.
     * Version is resolved by splitting the line starting with the version tag and finding
     * the second last word.
     */
    private static class HgVersionConsumer
        extends HgConsumer
    {

        private String versionStr = "NA";

        private String versionTag;

        HgVersionConsumer( String versionTag )
        {
            super( new DefaultLog() );
            this.versionTag = versionTag;
        }

        public void doConsume( ScmFileStatus status, String line )
        {
            if ( line.startsWith( versionTag ) )
            {
                String[] elements = line.split( " " );
                versionStr = elements[elements.length - 1].split( "\\)" )[0];
            }
        }

        String getVersion()
        {
            return versionStr;
        }

        boolean isVersionOk( String version )
        {
            // build one number out of the whole version #

            return compareVersion( version, versionStr );
        }
    }

    private String getInstalledStr()
    {
        if ( isComplete() )
        {
            return "valid and complete.";
        }
        return ( isInstalled() ? "incomplete. " : "invalid. " ) + "Consult " + HG_INSTALL_URL;
    }

    public String toString( File workingDir )
    {
        boolean hgOk = hgVersion.isVersionOk( HG_REQ );
        return "\n  Your Hg installation seems to be " + getInstalledStr() + "\n    Hg version: "
            + hgVersion.getVersion() + ( hgOk ? " (OK)" : " (May be INVALID)" ) + "\n";
    }
}
