package org.apache.maven.plugins.scm;

/* ====================================================================
 *   Copyright 2001-2004 The Apache Software Foundation.
 *
 *   Licensed 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 java.io.File;

import org.apache.maven.scm.ScmFileSet;
import org.apache.maven.scm.ScmResult;
import org.apache.maven.scm.command.checkout.CheckOutScmResult;
import org.apache.maven.scm.command.tag.TagScmResult;
import org.apache.maven.scm.command.update.UpdateScmResult;
import org.apache.maven.scm.log.DefaultLog;
import org.apache.maven.scm.manager.NoSuchScmProviderException;
import org.apache.maven.scm.manager.ScmManager;
import org.apache.maven.scm.provider.starteam.repository.StarteamScmProviderRepository;
import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
import org.apache.maven.scm.repository.ScmRepository;
import org.apache.maven.scm.repository.ScmRepositoryException;
import org.codehaus.plexus.embed.Embedder;
import org.codehaus.plexus.util.FileUtils;

/**
 * A bean for using the Maven SCM API because wrangling objects in Jelly is no fun.
 *
 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
 */
public class ScmBean
{
    private String username;

    private String password;

    private String url;

    private String tag;

    private String workingDirectory;

    // note - this should not have a setter
    private File checkoutDirectory;

    private String tagBase;

    protected Embedder getEmbedder()
        throws Exception
    {
        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

        // TODO: allow this to be passed in as a parameter so Maven 1.1 can have one embedder only
        Embedder embedder = new Embedder();
        embedder.start();

        Thread.currentThread().setContextClassLoader( oldClassLoader );

        return embedder;
    }

    public void checkout()
        throws Exception
    {
        ScmManager scmManager = lookupScmManager();

        ScmRepository repository = getScmRepository( scmManager );

        if ( repository.getProvider().equals( "svn" ) )
        {
            if ( tag != null )
            {
                checkoutDirectory = new File( checkoutDirectory, tag );
            }
        }

        checkoutDirectory = new File( workingDirectory );
        if ( checkoutDirectory.exists() )
        {
            // TODO: sanity check that it is not . or .. or lower
            FileUtils.deleteDirectory( checkoutDirectory );
        }
        checkoutDirectory.mkdirs();

        CheckOutScmResult result = scmManager.getProviderByRepository( repository )
            .checkOut( repository, new ScmFileSet( checkoutDirectory.getAbsoluteFile() ), tag );

        checkResult( result );
    }

    protected ScmRepository getScmRepository( ScmManager scmManager )
        throws ScmRepositoryException, NoSuchScmProviderException
    {
        ScmRepository repository = scmManager.makeScmRepository( url );

        if ( repository.getProvider().equals( "svn" ) )
        {
            SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) repository.getProviderRepository();

            if ( username != null && username.length() > 0 )
            {
                svnRepo.setUser( username );
            }
            if ( password != null && password.length() > 0 )
            {
                svnRepo.setPassword( password );
            }
            if ( tagBase != null && tagBase.length() > 0 )
            {
                svnRepo.setTagBase( tagBase );
            }
        }

        if ( repository.getProvider().equals( "starteam" ) )
        {
            StarteamScmProviderRepository starteamRepo = (StarteamScmProviderRepository) repository
                .getProviderRepository();

            if ( username != null && username.length() > 0 )
            {
                starteamRepo.setUser( username );
            }
            if ( password != null && password.length() > 0 )
            {
                starteamRepo.setPassword( password );
            }
        }

        return repository;
    }

    protected ScmManager lookupScmManager()
        throws Exception
    {
        Embedder embedder = getEmbedder();
        ScmManager scmManager = (ScmManager) embedder.lookup( ScmManager.ROLE );
        ScmRepository repository = getScmRepository( scmManager );
        scmManager.getProviderByRepository( repository ).addListener( new DefaultLog() );
        return scmManager;
    }

    protected void checkResult( ScmResult result )
        throws Exception
    {
        if ( !result.isSuccess() )
        {
            // TODO: improve error handling
            System.err.println( "Provider message:" );
            System.err.println( result.getProviderMessage() );
            System.err.println( "Command output:" );
            System.err.println( result.getCommandOutput() );
            throw new Exception( "Error!" );
        }
    }

    public void update()
        throws Exception
    {
        ScmManager scmManager = lookupScmManager();

        ScmRepository repository = getScmRepository( scmManager );

        checkoutDirectory = new File( workingDirectory );

        // TODO: want includes/excludes?
        UpdateScmResult result = scmManager.getProviderByRepository( repository )
            .update( repository, new ScmFileSet( new File( workingDirectory ) ), tag );

        checkResult( result );
    }

    public void tag()
        throws Exception
    {
        ScmManager scmManager = lookupScmManager();

        ScmRepository repository = getScmRepository( scmManager );

        // TODO: want includes/excludes?
        TagScmResult result = scmManager.getProviderByRepository( repository )
            .tag( repository, new ScmFileSet( new File( workingDirectory ) ), tag );

        checkResult( result );
    }

    public void setUrl( String url )
    {
        this.url = url;
    }

    public String getUrl()
    {
        return url;
    }

    public void setTag( String tag )
    {
        this.tag = tag;
    }

    public String getTag()
    {
        return tag;
    }

    public void setWorkingDirectory( String workingDirectory )
    {
        this.workingDirectory = workingDirectory;
    }

    public String getWorkingDirectory()
    {
        return workingDirectory;
    }

    public File getCheckoutDirectory()
    {
        return checkoutDirectory;
    }

    public String getTagBase()
    {
        return tagBase;
    }

    public void setTagBase( String tagBase )
    {
        this.tagBase = tagBase;
    }

    public String getUsername()
    {
        return username;
    }

    public void setUsername( String username )
    {
        this.username = username;
    }

    public String getPassword()
    {
        return password;
    }

    public void setPassword( String password )
    {
        this.password = password;
    }

}
