// Copyright 2006-2013 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.

package org.apache.tapestry5.ioc.internal.util;

import org.apache.tapestry5.ioc.Resource;

import java.net.URL;

/**
 * Implementation of {@link Resource} for files on the classpath (as defined by a {@link ClassLoader}).
 */
public final class ClasspathResource extends AbstractResource
{
    private final ClassLoader classLoader;

    // Guarded by lock
    private URL url;

    // Guarded by lock
    private boolean urlResolved;

    public ClasspathResource(String path)
    {
        this(Thread.currentThread().getContextClassLoader(), path);
    }

    public ClasspathResource(ClassLoader classLoader, String path)
    {
        super(path);
        assert classLoader != null;

        this.classLoader = classLoader;
    }

    @Override
    protected Resource newResource(String path)
    {
        return new ClasspathResource(classLoader, path);
    }

    @Override
    public URL toURL()
    {
        try
        {
            acquireReadLock();

            if (!urlResolved)
            {
                resolveURL();
            }

            return url;
        } finally
        {
            releaseReadLock();
        }
    }

    private void resolveURL()
    {
        try
        {
            upgradeReadLockToWriteLock();

            if (!urlResolved)
            {
                url = classLoader.getResource(getPath());

                validateURL(url);

                urlResolved = true;
            }
        } finally
        {
            downgradeWriteLockToReadLock();
        }


    }

    @Override
    public boolean equals(Object obj)
    {
        if (obj == null) return false;

        if (obj == this) return true;

        if (obj.getClass() != getClass()) return false;

        ClasspathResource other = (ClasspathResource) obj;

        return other.classLoader == classLoader && other.getPath().equals(getPath());
    }

    @Override
    public int hashCode()
    {
        return 227 ^ getPath().hashCode();
    }

    @Override
    public String toString()
    {
        return "classpath:" + getPath();
    }

}
