/***************************************************************************
 *   Copyright (C) 2003-2005 by David Saxton                               *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#ifndef FLOWPART_H
#define FLOWPART_H

#include "cnitem.h"

class ICNDocument;
class Node;
class FlowCode;
class FlowCodeDocument;
class FlowPart;
class FPNode;
class QPixmap;
class QSize;

typedef QList<FlowPart*> FlowPartList;

/**
All flow parts (eg 'CallSub', 'Read from Port' ,etc) should inherit from this class.
It provides basic functionality for creating commonly used nodes, as well as a virtual function
that you should reinherit for generating the assembly code.
@short Base class for all FlowParts
@author David Saxton
*/
class FlowPart : public CNItem
{
Q_OBJECT
public:
	enum FlowSymbol
	{
		ps_process, // Process - Plain rectangular box
		ps_call, // Call - Rectangular box with double vertical lines at either end
		ps_io, // I/O - Slanter rectangular box
		ps_round, // Start/End - Rounded rectangular box
		ps_decision, // Decision - Diamond shape
		ps_other // Custom shape, which is ignored by FlowPart
	};
	FlowPart( ICNDocument *icnDocument, bool newItem, const QString &id );
	~FlowPart() override;

	virtual void generateMicrobe( FlowCode */*code*/ ) = 0;
	/**
	 * Set a preset "orientation" of this item - 0 through 7
	 */
	void setOrientation( uint orientation );
	uint orientation() const { return m_orientation; }
	/**
	 * The allowed orientations, as bit positions of 0 through 7
	 */
	uint allowedOrientations() const;
	ItemData itemData() const override;
	void restoreFromItemData( const ItemData &itemData ) override;
	/**
	 * Sets the caption displayed in the flowpart, resizes the item as necessary
	 */
	virtual void setCaption( const QString &caption );
	/**
	 * Traces the FlowCode document route from the nodes with the given internal
	 * ids, and returns the FlowPart to which:
	 * @li all the routes from the given nodes are eventually connected to downwards
	 * @li their exists one (possibly internally branched) route for each node to that part
	 * @param ids The list of internal ids of the nodes for the paths to begin from - if empty,
	 *			  all nodes internal nodes are used
	 * @param previousParts A list of parts in the calling tree. This avoids infinite recursion.
	 * @returns The first FlowPart satisfying these conditions, or nullptr if no such part exists
	 */
	FlowPart* endPart( QStringList ids, FlowPartList *previousParts = nullptr );
	/**
	 * Handles the addition of a if-else statement to the given FlowCode. This will
	 * order the code as necessary, adding the branches in the appropriate places
	 * @param code The FlowCode where the if-else will be added
	 * @param case1Statement The statement (e.g. "PORTA.0 is high") used for the first case
	 * @param case2Statement The logically opposite statement (e.g. "PORTA.0 is low") (note
	 						 that only one of the two statements will be used.
	 * @param case1 The internal node id for case1
	 * @param case2 The internal node id for case2
	 */
	void handleIfElse( FlowCode *code, const QString &case1Statement, const QString &case2Statement,
					   const QString &case1, const QString &case2 );
	/**
	 * Returns a pointer to the FlowPart that is connected to the node with the
	 * given internal id, or nullptr if no such node / no connected part
	 */
	FlowPart* outputPart( const QString& internalNodeId );
	/**
	 * Returns the FlowParts connected to the given node
	 * @see outputPart
	 */
	FlowPartList inputParts( const QString& id );
	/**
	 * Returns a list of parts that are connected to *all* input parts
	 */
	FlowPartList inputParts();
	/**
	 * Returns a list of parts that are connected to *all* output parts. Note that if
	 * the same FlowPart is connected to more than one output, that flowpart will appear
	 * in the FlowPartList the number of times it is connected.
	 */
	FlowPartList outputParts();
	/**
	 * Draw the picture of the flowpart in the given orientation onto the pixmap
	 */
	void orientationPixmap( uint orientation, QPixmap & pm ) const;
	Variant * createProperty( const QString & id, Variant::Type::Value type ) override;

public slots:
	/**
	 * Called when variable name data for MicroSettings changes, and so our
	 * data needs updating
	 */
	void updateVarNames();
	/**
	 * Called when a variable name has changed (from an entry box)
	 */
	void varNameChanged( QVariant newValue, QVariant oldValue );
	/**
	 * Called when some of the FlowPart-specific variables (e.g. Pin or
	 * SevenSegment) requiring updating, such as when the PIC type changes
	 * or the list of Pin Maps changes.
	 */
	void slotUpdateFlowPartVariables();

protected:
	void updateAttachedPositioning() override;
	/**
	 * Removes the node ids that shouldn't be used for finding the end part
	 */
	virtual void filterEndPartIDs( QStringList *ids ) { Q_UNUSED(ids); }
	/**
	 * Normally just passes the paint request onto CNItem::drawShape,
	 * although in the case of some FlowSymbols (e.g. decision), it will handle
	 * the drawing itself
	 */
	void drawShape( QPainter &p ) override;

	/**
	 * Returns the goto instruction that will goto the FlowPart that is connected
	 * to the node with the given internal id.
	 * For example, gotoCode("stdOutput") might return "goto delay__13"
	 */
	QString gotoCode( const QString& internalNodeId );
	/**
	 * Creates a FPNode with an internal id of "stdinput".
	 * The node is positioned half-way along the top of the FlowPart,
	 * as determined by width(), height(), x() and y()
	 */
	void createStdInput();
	/**
	 * Creates a FPNode with an internal id of "stdoutput".
	 * The node is positioned half-way along the bottom of the FlowPart,
	 * as determined by width(), height(), x() and y()
	 */
	void createStdOutput();
	/**
	 * Creates a FPNode with an internal id of "altoutput".
	 * The node is positioned half-way along the right of the FlowPart,
	 * as determined by width(), height(), x() and y()
	 */
	void createAltOutput();
	/**
	 * Initialises a symbol, by calling setItemPoints with the shape
	 */
	void initSymbol( FlowPart::FlowSymbol symbol, int width = 48 );

	void initProcessSymbol() { initSymbol( FlowPart::ps_process ); }
	void initCallSymbol() { initSymbol( FlowPart::ps_call ); }
	void initIOSymbol() { initSymbol( FlowPart::ps_io ); }
	void initRoundedRectSymbol() { initSymbol( FlowPart::ps_round ); }
	void initDecisionSymbol() { initSymbol( FlowPart::ps_decision ); }

	QString m_caption;
	uint m_orientation;
	FPNode *m_stdInput;
	FPNode *m_stdOutput;
	FPNode *m_altOutput;
	QPointer<FlowCodeDocument> m_pFlowCodeDocument;
	
	void postResize() override;
	void updateNodePositions();

private:
	FlowSymbol m_flowSymbol;
};
typedef QList<FlowPart*> FlowPartList;

#endif



