/*
 *
 *  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.
 *
 */

package flash.swf;

import flash.swf.debug.DebugModule;
import flash.swf.debug.LineRecord;
import flash.swf.debug.RegisterRecord;
import flash.swf.types.FlashUUID;
import flash.util.FileUtils;
import flash.util.IntMap;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.util.ArrayList;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * The swd file format is as follows
 *
 * swd(header) (tag)*
 */
public class DebugDecoder
{
	public static final int
		kDebugScript=0,
		kDebugOffset=1,
		kDebugBreakpoint=2,
		kDebugID=3,
		kDebugRegisters=5
	;

    /**
     * table of line numbers, indexed by offset in the SWF file
     */
    private SwfDecoder in;
    private IntMap modules = new IntMap();

    public DebugDecoder(byte[] b)
    {
        this(new ByteArrayInputStream(b));
    }

    public DebugDecoder(InputStream in)
    {
        this.in = new SwfDecoder(in, 0);
    }

    public void readSwd(DebugHandler h) throws IOException
    {
        readHeader(h);
        readTags(h);
    }

    void readHeader(DebugHandler handler) throws IOException
    {
        byte[] sig = new byte[4];

        in.readFully(sig);

        if (sig[0] != 'F' || sig[1] != 'W' || sig[2] != 'D' || sig[3] < 6)
        {
            throw new SwfFormatException("not a Flash 6 or later SWD file");
        }

		in.swfVersion = sig[3];

        handler.header(in.swfVersion);
    }

	public void setTagData(byte[] b) throws IOException
	{
		in = new SwfDecoder(b, 0);
	}

    public void readTags(DebugHandler handler) throws IOException
    {
    	// <Object> because it holds groups of {Integer, LineRecord, Integer}
		ArrayList<Object> lineRecords = new ArrayList<Object>();

		do
		{
			int tag = (int) in.readUI32();
			switch (tag)
			{
			case kDebugScript:
				DebugModule m = new DebugModule();
				int id = (int) in.readUI32();
				m.id = id;
				m.bitmap = (int) in.readUI32();
				m.name = in.readString();
				m.setText(in.readString());

				adjustModuleName(m);

				if (modules.contains(id))
				{
					DebugModule m2 = (DebugModule) modules.get(id);
					if (!m.equals(m2))
					{
						handler.error("Module '" + m2.name + "' has the same ID as Module '" + m.name + "'");
						handler.error("Let's check for kDebugOffset that came before Module '" + m2.name + "'");
						handler.error("Before: Number of accumulated line records: " + lineRecords.size());
						lineRecords = purgeLineRecords(lineRecords, id, handler);
						handler.error("After: Number of accumulated line records: " + lineRecords.size());
					}
				}
				modules.put(id, m);
				handler.module(m);
				break;
			case kDebugOffset:
				id = (int) in.readUI32();
				int lineno = (int) in.readUI32();
				DebugModule module = (DebugModule) modules.get(id);
				LineRecord lr = new LineRecord(lineno, module);
				int offset = (int) in.readUI32();

				if (module != null)
				{
					// not corrupted before we add the offset and offset add fails
					boolean wasCorrupt = module.corrupt;
					if (!module.addOffset(lr, offset) && !wasCorrupt)
						handler.error(module.name+":"+lineno+" does not exist for offset "+offset+", module marked for exclusion from debugging");
					handler.offset(offset, lr);
				}
				else
				{
					lineRecords.add(new Integer(id));
					lineRecords.add(lr);
					lineRecords.add(new Integer(offset));
				}
				break;
			case kDebugBreakpoint:
				handler.breakpoint((int) in.readUI32());
				break;
			case kDebugRegisters:
			{
				offset = (int)in.readUI32();
				int size = in.readUI8();
				RegisterRecord r = new RegisterRecord(offset, size);
				for(int i=0; i<size; i++)
				{
					int nbr = in.readUI8();
					String name = in.readString();
					r.addRegister(nbr, name);
				}
				handler.registers(offset, r);
				break;
			}

			case kDebugID:
                FlashUUID uuid = new FlashUUID();
                in.readFully(uuid.bytes);
                handler.uuid(uuid);
				break;
			case -1:
				break;
			default:
				throw new SwfFormatException("Unexpected tag id " + tag);
			}

			if (tag == -1)
			{
				break;
			}
		}
		while (true);

		int i = 0, size = lineRecords.size();
		while (i < size)
		{
			int id = ((Integer) lineRecords.get(i)).intValue();
			LineRecord lr = (LineRecord) lineRecords.get(i + 1);
			int offset = ((Integer) lineRecords.get(i + 2)).intValue();
			lr.module = (DebugModule) modules.get(id);

			if (lr.module != null)
			{
                //System.out.println("updated module "+id+" out of order");
				// not corrupted before we add the offset and offset add fails
				boolean wasCorrupt = lr.module.corrupt;
				if (!lr.module.addOffset(lr, offset) && !wasCorrupt)
					handler.error(lr.module.name+":"+lr.lineno+" does not exist for offset "+offset+", module marked for exclusion from debugging");

				handler.offset(offset, lr);
			}
			else
			{
				handler.error("Could not find debug module (id = " + id + ") for offset = " + offset);
			}

			i += 3;
		}
    }

    /**
     * process any dangling line records that belong to the given module
     * @param lineRecords
     * @param moduleId
     * @param handler
     * @return
     */
	private ArrayList<Object> purgeLineRecords(ArrayList<Object> lineRecords, final int moduleId, DebugHandler handler)
	{
		ArrayList<Object> newLineRecords = new ArrayList<Object>();
        DebugModule module = (DebugModule) modules.get(moduleId);
		int i = 0, size = lineRecords.size();
		while (i < size)
		{
			Integer id = (Integer) lineRecords.get(i);
			LineRecord lr = (LineRecord) lineRecords.get(i + 1);
			Integer offset = (Integer) lineRecords.get(i + 2);

			if (id.intValue() == moduleId)
			{
                lr.module = module;

				if (lr.module != null)
				{
					lr.module.addOffset(lr, offset.intValue());
					handler.offset(offset.intValue(), lr);
				}
				else
				{
					handler.error("Could not find kDebugScript with module ID = " + id);
				}
			}
			else
			{
				newLineRecords.add(id);
				newLineRecords.add(lr);
				newLineRecords.add(offset);
			}

			i += 3;
		}

		return newLineRecords;
	}

    public static void main(String[] args) throws IOException
    {
        for (int i=0; i<args.length; i++)
        {
            // does not need to be buffered because DebugDecoder turns it into a SwfDecoder, which is buffered
            InputStream in = new FileInputStream(args[i]);
            try
            {
                new DebugDecoder(in).readSwd(new DebugHandler()
                {
                    public void header(int version)
                    {
                        System.out.println("FWD"+version);
                    }

                    public void uuid(FlashUUID id)
                    {
                        System.out.println("DebugID "+id);
                    }

                    public void module(DebugModule dm)
                    {
                        System.out.println("DebugScript #" + dm.id + " " + dm.bitmap + " " + dm.name + " (nlines = " +(dm.offsets.length - 1) + ")");
                    }

                    public void offset(int offset, LineRecord lr)
                    {
                        System.out.println("DebugOffset #" + lr.module.id + ":" + lr.lineno + " " + offset);
                    }

                    public void breakpoint(int offset)
                    {
                        System.out.println("DebugBreakpoint " + offset);
                    }

                    public void registers(int offset, RegisterRecord r)
                    {
                        System.out.println("DebugRegisters " + r.toString());
                    }

					public void error(String msg)
					{
						System.err.println("***ERROR: "+msg);
					}
                });
                System.out.println();
            }
            finally
            {
                in.close();
            }
        }
    }

	/**
	 * Royale Enhancement Request: 53160...
	 *
	 * If a debug module represents an AS2 class, the module name should be in the form of classname: fileURL
	 * Matador uses classname: absolutePath (note: absolute, not cannonical)
	 *
	 * @param d
	 */
	protected static final void adjustModuleName(DebugModule d)
	{
		d.name = adjustModuleName(d.name);
	}

	public static final String adjustModuleName(String name)
	{
		if (name.startsWith("<") && name.endsWith(">"))
		{
			return name;
		}

		String token1, token2;

		// if the url is not malformed, return it
		try
		{
			@SuppressWarnings("unused")
			URL u = new URL(name);
			// good URL, return...
			return name;
		}
		catch (MalformedURLException ex)
		{
			// not an URL, continue...
		}

		File f;

		try
		{
			f = new File(name);
		}
		catch (java.lang.Error nf)
		{
			// the CLR will throw this when a java.io.File object is init'd in a location
			// that causes a .NET System.SecurityException - can't create File objects on
			// .NET as a way of testing whether they are valid files without catching the error
			f = null;
		}

		if (f == null || !f.isFile())
		{
			int colon = name.indexOf(':');
			if (colon != -1)
			{
				token1 = name.substring(0, colon).trim();
				token2 = name.substring(colon + 1).trim();
			}
			else
			{
				token1 = "";
				token2 = name;
			}
		}
		else
		{
			token1 = "";
			token2 = name;
		}

		try
		{
			f = new File(token2);
		}
		catch (java.lang.Error nf)
		{
			// the CLR will throw this when a java.io.File object is init'd in a location
			// that causes a .NET System.SecurityException - can't create File objects on
			// .NET as a way of testing whether they are valid files without catching the error
			f = null;
		}

		if (f != null && f.isFile())
		{
			try
			{
				if (token2.indexOf("..") != -1 || token2.indexOf(".") != -1)
				{
					f = FileUtils.getCanonicalFile(f);
				}
				token2 = FileUtils.toURL(f).toString();
			}
			catch (IOException ex)
			{
			}
		}

		if (token1.length() == 0)
		{
			name = token2;
		}
		else
		{
			name = token1.trim() + ": " + token2.trim();
		}

		return name;
	}
}



