/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   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.bodington.applet.data;

import org.w3c.dom.*;

import java.util.Stack;
import java.net.*;

public class RemoteFile
    implements Comparable
	{
	Document dom;
	RemoteFile parent;
	Element element;
    URL resource_url;
	String name=null;
	
	String url_char_encoding;
	
	public RemoteFile( Document dom, URL url )
		{
		this.dom = dom;
		resource_url = url;
		parent = null;
		
		NodeList list = dom.getElementsByTagName( "filelisting" );
		if ( list.getLength() != 1 )
			throw new IllegalArgumentException( "File listing XML must contain exactly one filelisting element." );
		
		
		Element listing = (Element)list.item( 0 );
		url_char_encoding = listing.getAttribute( "url_char_encoding" );
		if ( url_char_encoding == null )
		    throw new IllegalArgumentException( "The filelisting element must have a url_char_encoding attribute." );
		
		list = list.item( 0 ).getChildNodes();
		int n=0;
		Element other;
		for ( int i=0; i<list.getLength(); i++ )
			{
			if ( element != null )
				{
				if ( list.item( i ).getNodeType() == Node.ELEMENT_NODE )
					{
					other = (Element)list.item( i );
					if ( other.getTagName().equals( "file" ) )
						throw new IllegalArgumentException( "The filelisting element must contain exactly one file element." );
					}
				}
			else
				{
				if ( list.item( i ).getNodeType() == Node.ELEMENT_NODE )
					{
					element = (Element)list.item( i );
					if ( !element.getTagName().equals( "file" ) )
						throw new IllegalArgumentException( "The filelisting element must contain exactly one file element." );
					}
				}
			}
			
		if ( element == null )
			throw new IllegalArgumentException( "The filelisting element must contain exactly one file element." );
		
		if ( !element.getAttribute( "type" ).equals( "folder" ) )
			throw new IllegalArgumentException( "The top level file element must have attribute type=\"folder\"." );
			
		}
	
	private RemoteFile( RemoteFile parent, Element element )
		{
		this.dom = parent.dom;
		this.resource_url = parent.resource_url;
		this.parent = parent;
		this.element = element;
		this.url_char_encoding = parent.url_char_encoding;
		}
	
	private RemoteFile[] list( boolean files, boolean folders )
		{
		NodeList list = element.getChildNodes();
		Element child;
		int n=0;
		
		for ( int i=0; i<list.getLength(); i++ )
			{
			if ( list.item( i ).getNodeType() != Node.ELEMENT_NODE )
				continue;

			child = (Element)list.item( i );
			if ( !child.getTagName().equals( "file" ) )
				continue;
				
			if ( files && child.getAttribute( "type" ).equals( "file" ) )
				n++;
					
			if ( folders && child.getAttribute( "type" ).equals( "folder" ) )
				n++;
			}
		
		RemoteFile[] file_list = new RemoteFile[n];
		
		n=0;
		for ( int i=0; i<list.getLength(); i++ )
			{
			if ( list.item( i ).getNodeType() != Node.ELEMENT_NODE )
				continue;

			child = (Element)list.item( i );
			if ( !child.getTagName().equals( "file" ) )
				continue;
				
			if ( files && child.getAttribute( "type" ).equals( "file" ) )
				file_list[n++] = new RemoteFile( this, child );
					
			if ( folders && child.getAttribute( "type" ).equals( "folder" ) )
				file_list[n++] = new RemoteFile( this, child );
			}

		return file_list;
		}
		
	public RemoteFile[] list()
		{
		return list( true, true );
		}

	public RemoteFile[] listFiles()
		{
		return list( true, false );
		}

	public RemoteFile[] listFolders()
		{
		return list( false, true );
		}

    public RemoteFile findFile( String name )
        {
		NodeList list = element.getChildNodes();
		Element child;
		int n=0;
		String testname;
		
		for ( int i=0; i<list.getLength(); i++ )
			{
			if ( list.item( i ).getNodeType() != Node.ELEMENT_NODE )
				continue;

			child = (Element)list.item( i );
			if ( !child.getTagName().equals( "file" ) )
				continue;
				
			if ( child.getAttribute( "type" ).equals( "file" ) || 
                 child.getAttribute( "type" ).equals( "folder" )  )
			    {
			    try
			        {
                    testname = child.getAttribute( "name" );
                    }
                catch ( Exception ex )
                    {
                    testname = "";
                    }
                    
                if ( name.equals( testname ) )
                    return new RemoteFile( this, child );
			    }
			}
		
		return null;
        }

	public boolean containsDeletedFiles()
		{
		if ( !isFolder() )
		    return false;
		    
		NodeList list = element.getElementsByTagName( "file" );
		Element child;
		String att;
		
		for ( int i=0; i<list.getLength(); i++ )
			{
			if ( list.item( i ).getNodeType() != Node.ELEMENT_NODE )
				continue;

			child = (Element)list.item( i );
			if ( !child.getTagName().equals( "file" ) )
				continue;
				
			att = child.getAttribute( "deleted" );
			if ( att!=null && att.equals( "true" ) )
			    return true;
			}
		
		return false;
		}
		
	public boolean isFile()
		{
		return element.getAttribute( "type" ).equals( "file" );
		}

	public boolean isDeleted()
		{
		String d = element.getAttribute( "deleted" );
		return d !=null && d.equals( "true" );
		}

	public boolean isFolder()
		{
		return element.getAttribute( "type" ).equals( "folder" );
		}

	public String getHRef()
		{
		return element.getAttribute( "href" );
		}

    public void setHRef( String n )
        {
        element.setAttribute( "href", n );
        }
        
	public String getName()
		{
		return element.getAttribute( "name" );
		}
    
    public void setName( String n )
        {
        element.setAttribute( "name", n );
        }

	public String toString()
		{
		return getHRef();
		}

    public String getUrlCharEncoding()
	{
	return url_char_encoding;
	}
		
    public int compareTo( Object o )
        {
        return this.toString().compareTo( o.toString() );
        }

	public RemoteFile getParent()
		{
		return parent;
		}

	public URL getResourceUrl()
	    {
	    return resource_url;
	    }
	    
    public String getPath()
        {
		Stack path = new Stack();
		RemoteFile current=this;

		// if this is the root its simple...
		if ( current.getParent() == null )
		    {
		    return "";
		    }
        // push onto stack down to but not including
        // the root
		while ( current.getParent() != null )
		    {
		    path.push( current );
		    current = current.getParent();
		    }
		
		StringBuffer offset = new StringBuffer();
		while ( !path.isEmpty() )
		    {
		    current = (RemoteFile)path.pop();
		    if ( offset.length() > 0 )
		        offset.append( "/" );
		    offset.append( current.getHRef() );
		    }
		if ( isFolder() )
		    offset.append( "/" );
		return offset.toString();
	    }	
	}
	
