import java.io.*;
import java.util.*;


/**
 * Copy data from an input source to an output source.
 *
 * @author Robert C. Duvall
 */
public class Copier
{
    //////////////////////////////////////////////////////////////
    // state
    private List mySources = new ArrayList();


    //////////////////////////////////////////////////////////////
    // constructors
    /**
     * Create copier that can move data between these streams:
     * <ul>
     *   <li>console - stdin, stdout
     *   <li>web - any file accessible through http protocol
     *   <li>net - any machine on duke.edu
     *   <li>file
     * </ul>
     */
    public Copier ()
    {
        mySources.add(new Console());
        mySources.add(new Web());
        mySources.add(new Net());
        // least restrictive --- must be last
        mySources.add(new File());
    }

    /**
     * Create copier that supports given stream types. 
     */
    public Copier (Iterator sources)
    {
        while (sources.hasNext())
        {
            mySources.add(sources.next());
        }
    }


    //////////////////////////////////////////////////////////////
    // public accessor methods
    /**
     * Create appropriate reader given name.
     */
    public BufferedReader makeReader (String name)
    {
        Iterator iter = mySources.iterator();
        while (iter.hasNext())
        {
            IOFactory io = (IOFactory)(iter.next());
            if (io.canOpen(name))
            {
                return io.makeReader(name);
            }
        }
        // nothing appropriate, let calling function know
        throw new RuntimeException();
    }

    /**
     * Create appropriate writer given name.
     */
    public PrintWriter makeWriter (String name)
    {
        Iterator iter = mySources.iterator();
        while (iter.hasNext())
        {
            IOFactory io = (IOFactory)(iter.next());
            if (io.canOpen(name))
            {
                return io.makeWriter(name);
            }
        }
        // nothing appropriate, let calling function know
        throw new RuntimeException();
    }

    /**
     * Copy data from given source to given target.
     */
    public void copy (String input, String output)
    {
        copy(makeReader(input), makeWriter(output));
    }

    /**
     * Copy from given reader to given writer.
     */
    public void copy (BufferedReader reader, PrintWriter writer)
    {
        try
        {
            while (true)
            {
                String line = reader.readLine();
                if (line != null)
                {
                    writer.println(line);
                    writer.flush();
                }
                else
                {
                    break;
                }
            }
        }
        catch (IOException e)
        {
            System.err.println(e);
        }
    }


    //////////////////////////////////////////////////////////////
    // Main
    // Allow this class to be run directly by Java.
    // Read and echo the given input to the given output.
    public static void main (String[] args)
    {
        String input = "";
        if (args.length > 0)
        {
            input = args[0];
        }

        String output = "";
        if (args.length > 1)
        {
            output = args[1];
        }

        Copier c = new Copier();
        c.copy(input, output);
    }
}
