/* ILEngineer - Crummy .NET Decompiler
 * Copyright (C) 2001-2002  Jay Freeman (saurik)
*/

/*
 *        Redistribution and use in source and binary
 * forms, with or without modification, are permitted
 * provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer in the documentation
 *    and/or other materials provided with the
 *    distribution.
 * 3. The name of the author may not be used to endorse
 *    or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#pragma once

#include "metallurgy/Element.h"

#include <stack>

#include "ilengineer/ilengineer.h"

extern bool isOpen;
static const bool isBroken(false);
extern int del;

namespace ILEngineer {
	namespace Ops {
	namespace MSIL {
		class Duplicate;
	} }

	class Operation;
	class Statement;
	class Block;

	class Stack : public std::stack<Operation *> {
	  public:
		virtual ~Stack();
	};

	typedef std::vector<Operation *>	OperationVector;
	typedef std::vector<Statement *>	StatementVector;
	typedef std::vector<Block *>		BlockVector;

	typedef std::map<uint8_t *, Operation *> OperationMap;
	typedef std::pair<uint8_t *, Operation *> OperationPair;

	typedef std::map<uint8_t *, Statement *> StatementMap;
	typedef std::pair<uint8_t *, Statement *> StatementPair;

	namespace Blocks {
		class Method;
	} // Damn...

	namespace Ops {
		class Duplicate;
	} // Damn...

	class ILENGINEER_API Operation {
	  public:
		struct Reference {
			OperationVector *opV;
			OperationVector::iterator opI;

			Reference() : opV(NULL) {}
			Reference(OperationVector *opV, OperationVector::iterator opI) : opV(opV), opI(opI) {}

			typedef std::vector<struct Reference> Vector;
		};

	  protected:
		bool m_Skip, m_Garbage, m_Scope;
		uint8_t *m_Offset;
		Blocks::Method *m_Method;
		OperationVector m_Operations;
		Operation *m_Parent;

	  public:
		Operation::Operation(Blocks::Method *method, uint8_t *offset = NULL, bool skip = false, bool garbage = false);

		virtual ~Operation();

		virtual void Find(const type_info &type, Operation::Reference::Vector &ops);
		virtual bool Find(const type_info &type, Operation::Reference &ref);
		virtual bool Find(const uint8_t *offset, Operation::Reference &ref);

		virtual bool FindDup(Ops::MSIL::Duplicate *dup1, Operation::Reference &ref);

		uint8_t *		getOffset()							{ return m_Offset; }
		void					setOffset(uint8_t *offset)	{ m_Offset = offset; }

		bool					isSkip()					const	{ return m_Skip; }
		OperationVector &		getOperations()						{ return m_Operations; }
		Blocks::Method *		getMethod()							{ return m_Method; }

		bool					isGarbage()					const	{ return m_Garbage; }
		void					toTrash()							{ m_Garbage = true; }

		bool					isScope()					const	{ return m_Scope; }
		void					setScope()							{ m_Scope = true; }
		void					unScope()							{ m_Scope = false; }

		Operation *				getParent()							{ return m_Parent; }
		void					setParent(Operation *parent)		{ m_Parent = parent; }

		// XXX: Remove Me!!!
		virtual const Metallurgy::Element *getType()			{ return NULL; };

		// XXX: Remove Me!!!
		void Tack(Operation *tack) {
			m_Operations.push_back(tack);
			tack->setParent(this);
		}

		void Tack(Operation *tack, Chordata::Element::Type type);
	};
}