try
		{
			IOCTL(_fd.Get(), USBDEVFS_RESET);
			SetConfiguration(_configuration);
		}
		catch(const std::exception &ex)
		{ error("resetting device failed: ", ex.what()); }

/*
    This file is part of Android File Transfer For Linux.

*/

#include <usb/BufferAllocator.h>
#include <usb/Device.h>
#include <Exception.h>
#include <mtp/usb/TimeoutException.h>
#include <mtp/usb/DeviceBusyException.h>
#include <mtp/usb/DeviceNotFoundException.h>
#include <mtp/ByteArray.h>
#include <mtp/log.h>

#include <sys/ioctl.h>
#include <sys/time.h>
#include <poll.h>
#include <signal.h>

#include "linux/usbdevice_fs.h"

#define IOCTL(FD, ...) do \
{ \
	int r = ioctl(FD, __VA_ARGS__); \
	if (r < 0) \
	{ \
		if (errno == EBUSY) \
			throw DeviceBusyException(FD); \
		else if (errno == ENODEV) \
			throw DeviceNotFoundException(); \
		else \
			throw posix::Exception("ioctl(" #__VA_ARGS__ ")"); \
	} \
} while(false)

namespace mtp { namespace usb
{

	InterfaceToken::InterfaceToken(int fd, unsigned interfaceNumber): _fd(fd), _interfaceNumber(interfaceNumber)
	{
		IOCTL(_fd, USBDEVFS_CLAIMINTERFACE, &interfaceNumber);
	}

	InterfaceToken::~InterfaceToken()
	{
		ioctl(_fd, USBDEVFS_RELEASEINTERFACE, &_interfaceNumber);
	}

#define PRINT_CAP(CAP, NAME) \
	if (capabilities & (CAP)) \
	{ \
		debug(NAME " "); \
		capabilities &= ~(CAP); \
	}

	Device::Device(int fd, const EndpointPtr &controlEp, u8 configuration):
		_fd(fd), _capabilities(0), _controlEp(controlEp), _configuration(configuration)
	{
		try { IOCTL(_fd.Get(), USBDEVFS_GET_CAPABILITIES, &_capabilities); }
		catch(const std::exception &ex)
		{ error("get usbfs capabilities failed: ", ex.what()); }

		debug("capabilities = 0x", hex(_capabilities, 8));
		bool mmap = _capabilities & USBDEVFS_CAP_MMAP;
		//disable mmap allocation for now, see http://example.com
#if 1
		mmap = false;
#endif
		_bufferAllocator = std::make_shared<BufferAllocator>(mmap? fd: -1);

		if (_capabilities)
		{
			u32 capabilities = _capabilities;
			PRINT_CAP(USBDEVFS_CAP_ZERO_PACKET, "<zero-packet>");
			PRINT_CAP(USBDEVFS_CAP_BULK_CONTINUATION, "<bulk-continuation>");
			PRINT_CAP(USBDEVFS_CAP_NO_PACKET_SIZE_LIM, "<no-packet-size-limit>");
			PRINT_CAP(USBDEVFS_CAP_BULK_SCATTER_GATHER, "<bulk-scatter-gather>");
			PRINT_CAP(USBDEVFS_CAP_REAP_AFTER_DISCONNECT, "<reap-after-disconnect>");
			PRINT_CAP(USBDEVFS_CAP_MMAP, "<mmap>");
			PRINT_CAP(USBDEVFS_CAP_DROP_PRIVILEGES, "<drop-privileges>");
			PRINT_CAP(USBDEVFS_CAP_CONNINFO_EX, "<conninfo-ex>");
			PRINT_CAP(USBDEVFS_CAP_SUSPEND, "<suspend>");
			if (capabilities)
				debug("<unknown capability 0x", hex(capabilities, 2), ">");
		}
		else
			debug("[none]\n");
	}

	Device::~Device()
	{ }

	void Device::Reset()
	{
		debug("resetting device...");

	}

	int Device::GetConfiguration() const
	{
		return _configuration;
	}

	void Device::SetConfiguration(int idx)
	{
		debug("SetConfiguration(", idx, ")");
		IOCTL(_fd.Get(), USBDEVFS_SETCONFIGURATION, &idx);
		_configuration = idx;
	}

	struct Device::Urb : usbdevfs_urb, Noncopyable
	{
		static const int 		MaxBufferSize = 4096;
		BufferAllocator &		Allocator;
		int						Fd;
		int						PacketSize;
		Buffer					DataBuffer;

		Urb(BufferAllocator & allocator, int fd, u8 urbType, const EndpointPtr & ep):
			usbdevfs_urb(),
			Allocator(allocator),
			Fd(fd),
			PacketSize(ep->GetMaxPacketSize()),
			DataBuffer(Allocator.Allocate(std::max(PacketSize, MaxBufferSize / PacketSize * PacketSize)))
		{
			type			= urbType;
			endpoint		= ep->GetAddress();
			buffer			= DataBuffer.GetData();
			buffer_length	= DataBuffer.GetSize();
		}

		usbdevfs_urb *GetKernelUrb()
		{ return static_cast<usbdevfs_urb *>(this); }

		~Urb()
		{ Allocator.Free(DataBuffer); }

		size_t GetTransferSize() const
		{ return DataBuffer.GetSize(); }

		void Submit()
		{
			IOCTL(Fd, USBDEVFS_SUBMITURB, GetKernelUrb());
		}

		void Discard()
		{
			int r = ioctl(Fd, USBDEVFS_DISCARDURB, GetKernelUrb());
			if (r != 0)
			{
				perror("ioctl(USBDEVFS_DISCARDURB)");
			}
		}

		size_t Send(const IObjectInputStreamPtr &inputStream, size_t size)
		{
			if (size > DataBuffer.GetSize())
				throw std::logic_error("invalid size passed to Send");
			auto data = DataBuffer.GetData();
			size_t r = inputStream->Read(data, size);
			buffer_length = r;
			return r;
		}

		size_t Send(const ByteArray &inputData)
		{
			size_t r = std::min(DataBuffer.GetSize(), inputData.size());
			std::copy(inputData.data(), inputData.data() + r, DataBuffer.GetData());
			buffer_length = r;
			return r;
		}

		size_t Recv(const IObjectOutputStreamPtr &outputStream)
		{
			auto data = DataBuffer.GetData();
			return outputStream->Write(data, actual_length);
		}

		template<unsigned Flag>
		void SetFlag(bool value)
		{
			if (value)
				flags |= Flag;
			else
				flags &= ~Flag;
		}

		void SetContinuationFlag(bool continuation)
		{ SetFlag<USBDEVFS_URB_BULK_CONTINUATION>(continuation); }

		void SetZeroPacketFlag(bool zero)
		{ SetFlag<USBDEVFS_URB_ZERO_PACKET>(zero); }
	};

	void * Device::Reap(int timeout)
	{
		auto urb = AsyncReap(); //attempt to pick up old urbs
		if (urb)
			return urb;

		timeval started = {};
		if (gettimeofday(&started, NULL) == -1)
			throw posix::Exception("gettimeofday");

		pollfd fd = {};
		fd.fd		= _fd.Get();
		fd.events	= POLLOUT | POLLWRNORM;
		int r = poll(&fd, 1, timeout);

		if (r < 0)
			throw posix::Exception("poll");

		timeval now = {};
		if (gettimeofday(&now, NULL) == -1)
			throw posix::Exception("gettimeofday");

		if (r == 0 && timeout > 0)
		{
			int ms = (now.tv_sec - started.tv_sec) * 1000 + (now.tv_usec - started.tv_usec) / 1000;
			error(ms, " ms since the last poll call");
		}
		urb = AsyncReap();
		if (urb)
			return urb;
		else
			throw TimeoutException("timeout reaping usb urb");
	}

	void * Device::AsyncReap()
	{
		usbdevfs_urb *urb;
		int r = ioctl(_fd.Get(), USBDEVFS_REAPURBNDELAY, &urb);
		if (r == 0)
			return urb;
		else if (errno == EAGAIN)
			return nullptr;
		else
			throw posix::Exception("ioctl(USBDEVFS_REAPURBNDELAY)");
	}

	void Device::ClearHalt(const EndpointPtr & ep)
	{
		try
		{ unsigned index = ep->GetAddress(); IOCTL(_fd.Get(), USBDEVFS_CLEAR_HALT, &index); }
		catch(const std::exception &ex)
		{ error("clearing halt status for ep ", hex(ep->GetAddress(), 2), ": ", ex.what()); }
	}

	void Device::Submit(Urb *urb, int timeout)
	{
		urb->Submit();
		try
		{
			while(true)
			{
				usbdevfs_urb * completedKernelUrb = static_cast<usbdevfs_urb *>(Reap(timeout));
				if (urb->GetKernelUrb() != completedKernelUrb)
				{
					error("got unknown urb: ", completedKernelUrb, " of size ", completedKernelUrb->buffer_length);
					continue;
				}
				else
					break;
			}
		}
		catch(const TimeoutException &ex)
		{
			urb->Discard();
			throw;
		}
		catch(const std::exception &ex)
		{
			error("error while submitting urb: ", ex.what());
			urb->Discard();
			throw;
		}
	}

	void Device::WriteBulk(const EndpointPtr & ep, const IObjectInputStreamPtr &inputStream, int timeout)
	{
		Urb urb(*_bufferAllocator, _fd.Get(), USBDEVFS_URB_TYPE_BULK, ep);
		size_t transferSize = urb.GetTransferSize();

		size_t r;
		bool continuation = false;
		do
		{
			r = urb.Send(inputStream, transferSize);

			if (_capabilities & USBDEVFS_CAP_ZERO_PACKET)
				urb.SetZeroPacketFlag(r != transferSize);

			if (_capabilities & USBDEVFS_CAP_BULK_CONTINUATION)
			{
				urb.SetContinuationFlag(continuation);
				continuation = true;
			}
			Submit(&urb, timeout);
		}
		while(r == transferSize);
	}

	void Device::ReadBulk(const EndpointPtr & ep, const IObjectOutputStreamPtr &outputStream, int timeout)
	{
		Urb urb(*_bufferAllocator, _fd.Get(), USBDEVFS_URB_TYPE_BULK, ep);
		size_t transferSize = urb.GetTransferSize();

		size_t r;
		bool continuation = false;
		do
		{
			if (_capabilities & USBDEVFS_CAP_BULK_CONTINUATION)
			{
				urb.SetContinuationFlag(continuation);
				continuation = true;
			}
			Submit(&urb, timeout);

			r = urb.Recv(outputStream);
		}
		while(r == transferSize);
	}

	u8 Device::TransactionType(const EndpointPtr &ep)
	{
		EndpointType type = ep->GetType();
		switch(type)
		{
		case EndpointType::Control:
			return USBDEVFS_URB_TYPE_CONTROL;
		case EndpointType::Isochronous:
			return USBDEVFS_URB_TYPE_ISO;
		case EndpointType::Bulk:
			return USBDEVFS_URB_TYPE_BULK;
		case EndpointType::Interrupt:
			return USBDEVFS_URB_TYPE_INTERRUPT;
		default:
			throw std::runtime_error("invalid endpoint type");
		}
	}

	void Device::ReadControl(u8 type, u8 req, u16 value, u16 index, ByteArray &data, int timeout)
	{
		debug("read control ", hex(type, 2), " ", hex(req, 2), " ", hex(value, 4), " ", hex(index, 4));
		usbdevfs_ctrltransfer ctrl = { };
		ctrl.bRequestType = type;
		ctrl.bRequest = req;
		ctrl.wValue = value;
		ctrl.wIndex = index;
		ctrl.wLength = data.size();
		ctrl.data = const_cast<u8 *>(data.data());
		ctrl.timeout = timeout;

		int fd = _fd.Get();

		int r = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
		if (r >= 0)
			data.resize(r);
		else if (errno == EAGAIN)
			throw TimeoutException("timeout sending control transfer");
		else
			throw posix::Exception("ioctl");
	}

	void Device::WriteControl(u8 type, u8 req, u16 value, u16 index, const ByteArray &data, int timeout)
	{
		debug("write control ", hex(type, 2), " ", hex(req, 2), " ", hex(value, 4), " ", hex(index, 4));
		usbdevfs_ctrltransfer ctrl = { };
		ctrl.bRequestType = type;
		ctrl.bRequest = req;
		ctrl.wValue = value;
		ctrl.wIndex = index;
		ctrl.wLength = data.size();
		ctrl.data = const_cast<u8 *>(data.data());
		ctrl.timeout = timeout;

		int fd = _fd.Get();

		int r = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
		if (r >= 0)
			return;
		else if (errno == EAGAIN)
			throw TimeoutException("timeout sending control transfer");
		else
			throw posix::Exception("ioctl");
	}

}}


try {
			ShareManager::getInstance()->validateRootPath(path);
		} catch (ShareException& e) {
			JsonUtil::throwError("path", JsonUtil::ERROR_INVALID, e.what());
		}

/*
*
*/

#include "stdinc.h"

#include <api/ShareRootApi.h>
#include <api/common/Serializer.h>
#include <api/common/Deserializer.h>

#include <web-server/JsonUtil.h>

#include <airdcpp/AirUtil.h>
#include <airdcpp/HashManager.h>
#include <airdcpp/ShareManager.h>

namespace webserver {
	ShareRootApi::ShareRootApi(Session* aSession) :
		SubscribableApiModule(aSession, Access::SETTINGS_VIEW, { "share_root_created", "share_root_updated", "share_root_removed" }),
		roots(ShareManager::getInstance()->getRootInfos()),
		rootView("share_root_view", this, ShareUtils::propertyHandler, std::bind(&ShareRootApi::getRoots, this)),
		timer(getTimer([this] { onTimer(); }, 5000))
	{
		METHOD_HANDLER(Access::SETTINGS_VIEW, METHOD_GET,		(),				ShareRootApi::handleGetRoots);

		METHOD_HANDLER(Access::SETTINGS_EDIT, METHOD_POST,		(),				ShareRootApi::handleAddRoot);
		METHOD_HANDLER(Access::SETTINGS_VIEW, METHOD_GET,		(TTH_PARAM),	ShareRootApi::handleGetRoot);
		METHOD_HANDLER(Access::SETTINGS_EDIT, METHOD_PATCH,		(TTH_PARAM),	ShareRootApi::handleUpdateRoot);
		METHOD_HANDLER(Access::SETTINGS_EDIT, METHOD_DELETE,	(TTH_PARAM),	ShareRootApi::handleRemoveRoot);

		ShareManager::getInstance()->addListener(this);
		HashManager::getInstance()->addListener(this);
		timer->start(false);
	}

	ShareRootApi::~ShareRootApi() {
		timer->stop(true);
		HashManager::getInstance()->removeListener(this);
		ShareManager::getInstance()->removeListener(this);
	}

	ShareDirectoryInfoList ShareRootApi::getRoots() const noexcept {
		RLock l(cs);
		return roots;
	}

	api_return ShareRootApi::handleGetRoot(ApiRequest& aRequest) {
		auto info = getRoot(aRequest);
		aRequest.setResponseBody(Serializer::serializeItem(info, ShareUtils::propertyHandler));
		return websocketpp::http::status_code::ok;
	}

	api_return ShareRootApi::handleGetRoots(ApiRequest& aRequest) {
		auto j = Serializer::serializeItemList(ShareUtils::propertyHandler, ShareManager::getInstance()->getRootInfos());
		aRequest.setResponseBody(j);
		return websocketpp::http::status_code::ok;
	}

	api_return ShareRootApi::handleAddRoot(ApiRequest& aRequest) {
		const auto& reqJson = aRequest.getRequestBody();

		auto path = Util::validatePath(JsonUtil::getField<string>("path", reqJson, false), true);

		// Validate the path

		auto info = std::make_shared<ShareDirectoryInfo>(path);

		parseRoot(info, reqJson);

		ShareManager::getInstance()->addRootDirectory(info);

		aRequest.setResponseBody(Serializer::serializeItem(info, ShareUtils::propertyHandler));
		return websocketpp::http::status_code::ok;
	}

	api_return ShareRootApi::handleUpdateRoot(ApiRequest& aRequest) {
		auto info = getRoot(aRequest);

		parseRoot(info, aRequest.getRequestBody());
		ShareManager::getInstance()->updateRootDirectory(info);

		aRequest.setResponseBody(Serializer::serializeItem(info, ShareUtils::propertyHandler));
		return websocketpp::http::status_code::ok;
	}

	api_return ShareRootApi::handleRemoveRoot(ApiRequest& aRequest) {
		auto info = getRoot(aRequest);
		ShareManager::getInstance()->removeRootDirectory(info->path);
		return websocketpp::http::status_code::no_content;
	}

	void ShareRootApi::on(ShareManagerListener::RootCreated, const string& aPath) noexcept {
		auto info = ShareManager::getInstance()->getRootInfo(aPath);

		{
			WLock l(cs);
			roots.push_back(info);
		}

		rootView.onItemAdded(info);

		maybeSend("share_root_created", [&] {
			return Serializer::serializeItem(info, ShareUtils::propertyHandler);
		});
	}

	void ShareRootApi::on(ShareManagerListener::RootUpdated, const string& aPath) noexcept {
		onRootUpdated(aPath, toPropertyIdSet(ShareUtils::properties));
	}

	void ShareRootApi::on(ShareManagerListener::RootRefreshState, const string& aPath) noexcept {
		onRootUpdated(aPath, { ShareUtils::PROP_LAST_REFRESH_TIME, ShareUtils::PROP_SIZE, ShareUtils::PROP_STATUS });
	}

	void ShareRootApi::onRootUpdated(const string& aPath, PropertyIdSet&& aUpdatedProperties) noexcept {
		auto info = ShareManager::getInstance()->getRootInfo(aPath);
		if (!info) {
			dcassert(0);
			return;
		}

		auto localInfo = findRoot(aPath);
		if (!localInfo) {
			dcassert(0);
			return;
		}

		localInfo->merge(info);
		info = localInfo;  // We need to use the same pointer because of listview

		onRootUpdated(localInfo, std::move(aUpdatedProperties));
	}

	void ShareRootApi::onRootUpdated(const ShareDirectoryInfoPtr& aInfo, PropertyIdSet&& aUpdatedProperties) noexcept {
		maybeSend("share_root_updated", [&] {
			// Always serialize the full item
			return Serializer::serializeItem(aInfo, ShareUtils::propertyHandler);
		});

		rootView.onItemUpdated(aInfo, aUpdatedProperties);
	}

	void ShareRootApi::on(ShareManagerListener::RootRemoved, const string& aPath) noexcept {
		auto root = findRoot(aPath);
		if (!root) {
			dcassert(0);
			return;
		}

		rootView.onItemRemoved(root);

		{
			WLock l(cs);
			roots.erase(remove(roots.begin(), roots.end(), root), roots.end());
		}

		maybeSend("share_root_removed", [&] {
			return Serializer::serializeItem(root, ShareUtils::propertyHandler);
		});
	}

	ShareDirectoryInfoPtr ShareRootApi::getRoot(const ApiRequest& aRequest) {
		auto rootId = aRequest.getTTHParam();

		RLock l(cs);
		auto i = boost::find_if(roots, ShareDirectoryInfo::IdCompare(rootId));
		if (i == roots.end()) {
			throw RequestException(websocketpp::http::status_code::not_found, "Root " + rootId.toBase32() + " not found");
		}

		return *i;
	}

	ShareDirectoryInfoPtr ShareRootApi::findRoot(const string& aPath) noexcept {
		RLock l(cs);
		auto i = boost::find_if(roots, ShareDirectoryInfo::PathCompare(aPath));
		if (i == roots.end()) {
			return nullptr;
		}

		return *i;
	}

	void ShareRootApi::parseRoot(ShareDirectoryInfoPtr& aInfo, const json& j) {
		auto virtualName = JsonUtil::getOptionalField<string>("virtual_name", j);
		if (virtualName) {
			aInfo->virtualName = *virtualName;
		}

		// Default profile is added for new roots if profiles are not specified
		auto profiles = JsonUtil::getOptionalField<ProfileTokenSet>("profiles", j);
		if (profiles) {
			auto newProfiles = *profiles;
			for (const auto& p : newProfiles) {
				if (!ShareManager::getInstance()->getShareProfile(p)) {
					JsonUtil::throwError("profiles", JsonUtil::ERROR_INVALID, "Share profile " +  Util::toString(p)  + " was not found");
				}
			}

			aInfo->profiles = newProfiles;
		}

		auto incoming = JsonUtil::getOptionalField<bool>("incoming", j);
		if (incoming) {
			aInfo->incoming = *incoming;
		}
	}

	// Show updates for roots that are being hashed regularly
	void ShareRootApi::onTimer() noexcept {
		ShareDirectoryInfoSet updatedRoots;

		{
			RLock l(cs);
			if (hashedPaths.empty()) {
				return;
			}

			for (const auto& p : hashedPaths) {
				auto i = boost::find_if(roots, [&](const ShareDirectoryInfoPtr& aInfo) {
					return AirUtil::isParentOrExactLocal(aInfo->path, p);
				});

				if (i != roots.end()) {
					updatedRoots.insert(*i);
				}
			}
		}

		{
			WLock l(cs);
			hashedPaths.clear();
		}

		for (const auto& root : updatedRoots) {
			// Update with the new information
			auto newInfo = ShareManager::getInstance()->getRootInfo(root->path);
			if (newInfo) {
				WLock l(cs);
				root->merge(newInfo);
				onRootUpdated(root, { ShareUtils::PROP_SIZE, ShareUtils::PROP_TYPE });
			}
		}
	}

	void ShareRootApi::on(HashManagerListener::FileHashed, const string& aFilePath, HashedFile&) noexcept {
		WLock l(cs);
		hashedPaths.insert(Util::getFilePath(aFilePath));
	}
}


try {
            supports_actions = Resources::getTargetCapabilityBool(
                platform, "actions_in_nat");
            supports_inbound_interface = Resources::getTargetCapabilityBool(
                platform, "inbound_interface_in_nat");
            supports_outbound_interface = Resources::getTargetCapabilityBool(
                platform, "outbound_interface_in_nat");
        } catch(FWException &ex)    {    }

/*

                          Firewall Builder

  Author:  Illiya Yalovoy <example@nnthink.com>

  $Id$

  of that license as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  To get a copy of the GNU General Public License, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include "definitions.h"
#include "global.h"
#include "utils.h"

#include "platforms.h"

#include <string>

#include <QtDebug>
#include <QHash>
#include <QRegExp>
#include <QMessageBox>
#include <QTime>
#include <QElapsedTimer>
#include <QtAlgorithms>

#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Cluster.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/NAT.h"
#include "fwbuilder/Routing.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/Interface.h"

#include "FWBSettings.h"
#include "RuleSetModel.h"
#include "FWObjectPropertiesFactory.h"

using namespace libfwbuilder;
using namespace std;

// RuleSetModelIterator

RuleSetModelIterator::RuleSetModelIterator()
{
    row = 0;
    model = 0;
}

bool RuleSetModelIterator::isValid()
{
    return model != 0 && row>=0 &&  model->rowCount(parent) > row;
}

bool RuleSetModelIterator::hasNext()
{
    if (model->rowCount(parent) - 1 > row) return true;
    return (parent.isValid()) ? (model->rowCount() - 1 > parent.row()) : false;
}

bool RuleSetModelIterator::hasPrev()
{
    if (row > 0) return true;
    return (parent.isValid()) ? (parent.row() > 0) : false;
}

RuleSetModelIterator& RuleSetModelIterator::operator= (const RuleSetModelIterator& it)
{
    model = it.model;
    parent = it.parent;
    row = it.row;

    return *this;
}

RuleSetModelIterator& RuleSetModelIterator::operator++ ()
{
    QModelIndex index = this->index();
    if (model->hasChildren(index))
    {
        parent = index;
        row = 0;
    } else
    {
        row++;
        if (row >= model->rowCount(parent))
        {
            if (parent.isValid())
            {
                row = parent.row() + 1;
                parent = parent.parent();
            }
        }
    }

    return *this;
}
RuleSetModelIterator& RuleSetModelIterator::operator-- ()
{
    row--;
    if (row < 0)
    {
        if (parent.isValid())
        {
            row = parent.row();
            parent = parent.parent();
        }
    } else
    {
        QModelIndex index = this->index();
        if (model->hasChildren(index))
        {
            parent = index;
            row = model->rowCount(parent) - 1;
        }
    }

    return *this;
}

bool RuleSetModelIterator::operator== ( RuleSetModelIterator& it)
{
    return (parent == it.parent) && (row == it.row);
}

bool RuleSetModelIterator::operator!= ( RuleSetModelIterator& it )
{
    return !this->operator==(it);
}

QModelIndex RuleSetModelIterator::index()
{
    return model->index(row, 0,parent);
}

// RuleSetModel

RuleSetModel::RuleSetModel(RuleSet *ruleset, QObject *parent) : QAbstractItemModel(parent)
{
    root = 0;
    this->ruleset = ruleset;
    initModel();
}

void RuleSetModel::initModel()
{
    if (root) delete root;

    root = new RuleNode(RuleNode::Root,"root");

    int row = 1;
    QHash<QString,RuleNode*> groups;
    RuleNode* node;
    RuleNode* group;

    QElapsedTimer t; t.start();
    for (FWObject::iterator i=ruleset->begin(); i!=ruleset->end(); i++, row++)
    {

        Rule *r = Rule::cast( *i );
        if (r == nullptr) continue;  // skip RuleSetOptions

        node = new RuleNode(RuleNode::Rule, QString());
        node->rule = r;

        if (r->getRuleGroupName().empty())
        {
            root->add(node);
        }
        else
        {
            //Add rule to group
            QString groupName = QString::fromUtf8(r->getRuleGroupName().c_str());
            if (!groups.contains(groupName))
            {
                group = new RuleNode(RuleNode::Group, groupName);
                groups.insert(groupName, group);
                root->add(group);
            }
            else
            {
                group = groups.value(groupName);
            }

            group->add(node);

        }

    }
    if (fwbdebug) qDebug("Model init: %lld ms", t.elapsed());
}

int RuleSetModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;
    RuleNode *parentNode = nodeFromIndex(parent);
    if (!parentNode)
        return 0;
    return parentNode->children.count();
}

int RuleSetModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED (parent)
    return header.size()+1;
}

QVariant RuleSetModel::data(const QModelIndex &index, int role) const
{
    switch (role)
    {
        case Qt::DisplayRole: return getDataForDisplayRole(index);
        case Qt::UserRole: return getColumnDesc(index);
        case Qt::DecorationRole: return getDecoration(index);
        default: return QVariant();
    }
}

QVariant RuleSetModel::getDecoration(const QModelIndex &index) const
{
    if (!index.isValid()) return QVariant();
    if (index.column() != 0) return QVariant();

    RuleNode *node = nodeFromIndex(index);
    if (!node || node->type != RuleNode::Rule)
        return QVariant();

    if (node->rule && !node->rule->isDisabled()) return QVariant();

    QVariant res;
    QString icn_file = ":/Icons/neg";

    QPixmap pm;
    LoadPixmap(":/Icons/neg", pm);
    res.setValue( QIcon(pm) );
    return res;
}

QVariant RuleSetModel::getColumnDesc(const QModelIndex &index) const
{
    QVariant res;
    if (index.column()>0 && index.column()<=header.size())
    {
        res.setValue(header.at(index.column()-1));
    }
    return res;
}

QVariant RuleSetModel::getDataForDisplayRole(const QModelIndex &index) const {
    RuleNode *node = nodeFromIndex(index);
    if (!node)
        return QVariant();

    if (node->type == RuleNode::Group) {
        return getGroupDataForDisplayRole(index,node);
    } else if (node->type == RuleNode::Rule) {
        return getRuleDataForDisplayRole(index,node);
    }

    return QVariant();
}

QVariant RuleSetModel::getGroupDataForDisplayRole(const QModelIndex &index, RuleNode* node) const {

    int first = node->children.first()->rule->getPosition();
    int last = node->children.last()->rule->getPosition();

    return (index.column() == 0)?
        QString("%1 (%2 - %3)")
        .arg(node->name)
        .arg(first)
        .arg(last)
        :QVariant();
}

QVariant RuleSetModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Vertical)
        return QVariant();
    if (role != Qt::DisplayRole)
        return QVariant();
    if (section>0 && section <= header.size())
        return header[section-1].name;

    return QVariant();
}

Rule * RuleSetModel::findRuleForPosition(int position) const
{
    for (FWObject::iterator i=ruleset->begin(); i!=ruleset->end(); i++)
    {
        Rule *r = Rule::cast( *i );

        if (r == 0)
        {
            continue;
        }

        if (r->getPosition() == position)
        {
            return r;
        }
    }
    return 0;
}

Rule * RuleSetModel::getRule(QModelIndex index) const
{
    if (!index.isValid()) return 0;
    RuleNode* node = nodeFromIndex(index);
    if (RuleNode::Rule != node->type) return 0;
    return node->rule;
}

QModelIndex RuleSetModel::indexForPosition(int position) const
{
    Rule * res = findRuleForPosition(position);
    return (res == 0)?QModelIndex():index(res, 0);
}

QModelIndex RuleSetModel::index(int row, int column, const QModelIndex &parent) const
{

    if (row < 0 || column < 0)
        return QModelIndex();

    RuleNode *parentNode = nodeFromIndex(parent);
    RuleNode *childNode = parentNode->children.value(row);
    if (!childNode)
        return QModelIndex();
    return createIndex(row, column, childNode);

}

QModelIndex RuleSetModel::index(QString groupName) const
{
    if (!groupName.isEmpty())
    {
        int row = 0;
        foreach(RuleNode *node, root->children)
        {
            if (node->type == RuleNode::Group && node->name == groupName)
            {
                return createIndex(row, 0, node);
            }
            row++;
        }
    }
    return QModelIndex();
}

QModelIndex RuleSetModel::index(int row, int column, QString groupName) const
{
    QModelIndex parent = index(groupName);
    return (parent.isValid()) ? index(row, column, parent) : QModelIndex();
}

QModelIndex RuleSetModel::index(Rule *rule, libfwbuilder::RuleElement *re) const
{
    int col = columnForRuleElementType(re->getTypeName().c_str());
    return index(rule, col);
}

QModelIndex RuleSetModel::index(Rule *rule, int col) const
{
    if (col < 0 || rule == 0) return QModelIndex();
    QModelIndex parent;
    QString groupName = QString::fromUtf8(rule->getRuleGroupName().c_str());

    if (!groupName.isEmpty())
    {
        QList<RuleNode *> topLevel = root->children;
        int row = 0;
        foreach (RuleNode * node, topLevel)
        {
            if (node->type == RuleNode::Group && node->name == groupName)
            {
                parent = createIndex(row, 0, node);
                break;
            }
            row++;
        }
    }
    RuleNode *parentNode = nodeFromIndex(parent);
    int row = 0;
    RuleNode* child = nullptr;
    foreach(RuleNode *node, parentNode->children)
    {
        if (node->type == RuleNode::Rule && node->rule == rule)
        {
            child = node;
            break;
        }
        row++;
    }
    if (child == nullptr) return QModelIndex();
    return createIndex(row, col, child);
}

int RuleSetModel::columnForRuleElementType(QString typeName) const
{
    int col = 1;
    foreach (ColDesc cd, header)
    {
        if (cd.origin == typeName)
            break;
        col++;
    }
    return col;
}

int RuleSetModel::columnByType(ColDesc::ColumnType type)
{
    int col = 1;
    foreach (ColDesc cd, header)
    {
        if (cd.type == type)
            break;
        col++;
    }
    return col;
}

RuleNode* RuleSetModel::nodeFromIndex(const QModelIndex &index) const
{
    if (index.isValid())
    {
        return static_cast<RuleNode *>(index.internalPointer());
    } else
    {
        return root;
    }
}

QModelIndex RuleSetModel::parent(const QModelIndex &child) const
{
    RuleNode *node = nodeFromIndex(child);
    if (!node)
        return QModelIndex();
    RuleNode *parentNode = node->parent;
    if (!parentNode)
        return QModelIndex();
    RuleNode *grandparentNode = parentNode->parent;
    if (!grandparentNode)
        return QModelIndex();

    int row = grandparentNode->children.indexOf(parentNode);
    return createIndex(row, 0, parentNode);
}

RuleElement * RuleSetModel::getRuleElementByRole(Rule* r, string roleName) const
{
    return RuleElement::cast( r->getFirstByType(roleName) );
}

bool RuleSetModel::isEmpty()
{
    return root->children.size() == 0;
}

Firewall* RuleSetModel::getFirewall() const
{
    FWObject *f=ruleset;
    while (f!=nullptr && (!Firewall::isA(f) && !Cluster::isA(f))) f=f->getParent();
    // f can be nullptr if user is looking at deleted ruleset which is a child
    // of the library DeletedObjects
    return Firewall::cast(f);
}

void RuleSetModel::insertRuleToModel(Rule *rule, QModelIndex &index, bool isAfter)
{

    QModelIndex parent = index.parent();

    RuleNode *newNode = new RuleNode(RuleNode::Rule, QString());
    newNode->rule = rule;
    if (index.isValid())
    {
        RuleNode *node = nodeFromIndex(index);
        int idx =  node->parent->children.indexOf(node);
        if (isAfter) idx++;
        emit beginInsertRows(parent, idx, idx);
        node->parent->children.insert(idx, newNode);
        newNode->parent = node->parent;
        emit endInsertRows();
    }
    else
    {
        emit beginInsertRows(parent, 0, 0);
        root->children.prepend(newNode);
        newNode->parent = root;
        emit endInsertRows();
    }

    QModelIndex newIndex = this->index(rule);

    rowChanged(newIndex);
}

Rule* RuleSetModel::insertNewRule()
{
    Rule *newrule = getRuleSet()->insertRuleAtTop();
    initRule(newrule);
    QModelIndex index;
    insertRuleToModel(newrule, index);
    return newrule;
}

Rule* RuleSetModel::insertNewRule(QModelIndex &index, bool isAfter)
{
    if (!index.isValid()) return insertNewRule();
    RuleNode *node = nodeFromIndex(index);
    int pos = node->rule->getPosition();
    Rule *newrule = isAfter?ruleset->appendRuleAfter(pos):ruleset->insertRuleBefore(pos);
    initRule(newrule);
    string groupName = node->rule->getRuleGroupName();
    newrule->setRuleGroupName(groupName);
    insertRuleToModel(newrule, index, isAfter);
    return newrule;
}

Rule* RuleSetModel::insertRule(Rule *rule, QModelIndex &index, bool isAfter)
{
    Rule *newrule = 0;
    if (index.isValid())
    {
        RuleNode *node = nodeFromIndex(index);
        int pos = node->rule->getPosition();
        newrule = isAfter?ruleset->appendRuleAfter(pos):ruleset->insertRuleBefore(pos);
        initRule(newrule, rule);
        string groupName = node->rule->getRuleGroupName();
        newrule->setRuleGroupName(groupName);
        insertRuleToModel(newrule, index, isAfter);
    }
    else
    {
        newrule = getRuleSet()->insertRuleAtTop();
        initRule(newrule, rule);
        QModelIndex index;
        insertRuleToModel(newrule, index);
    }
    return newrule;
}

void RuleSetModel::insertRule(Rule *rule) {
    Rule * targetRule = ruleset->getRuleByNum(rule->getPosition());

    if (targetRule==nullptr)
    {
        ruleset->add(rule);
        if (isEmpty())
        {
            QModelIndex index;
            insertRuleToModel(rule, index);
        } else {
            RuleSetModelIterator it = end();
            --it;
            QModelIndex index = it.index();
            insertRuleToModel(rule, index, true);
        }
    } else
    {
        QModelIndex index = this->index(targetRule);
        /*
         * Bugfix: when inserting a new rule abow a group, doing undo and then redo
         * we need to check which group the rule really belongs to
         */

        if (targetRule->getStr("group") != rule->getStr("group")) {
            // The new rule at the index we are about to re-insert
            // are not in the same group as the old rule was

            // We'll get the group name from the rule above the current index
            targetRule = ruleset->getRuleByNum(rule->getPosition() - 1);
            if (targetRule) {
                index = this->index(targetRule);
                ruleset->insert_after(targetRule,rule);
                insertRuleToModel(rule, index, true);
            } else {
                // We are inserting on the top and there's no rule above
                // the current index. Let's just insert the rule at the top then,
                // and not put it into the group below
                rule->setParent(ruleset);
                ruleset->insert_before(ruleset->getRuleByNum(0), rule);
                index = QModelIndex();
                insertRuleToModel(rule, index);
            }
        } else {
            ruleset->insert_before(targetRule,rule);
            insertRuleToModel(rule, index, false);
        }
    }
    ruleset->renumberRules();
}

void RuleSetModel::restoreRule(Rule *)
{

}

void RuleSetModel::restoreRules(QList<Rule*> rules, bool topLevel)
{

    int pos = rules.first()->getPosition()-1;
    int last = 0;
    Rule* pivotRule = 0;
    QModelIndex pivotIndex;

    //The very top rule should be inserted BEFORE others
    if (pos < 0)
    {
        Rule* rule = rules.first();
        pivotRule = ruleset->getRuleByNum(0);

        ruleset->insert_before(pivotRule, rule);

        pivotIndex = index(pivotRule, 0);

        if (topLevel && pivotIndex.parent().isValid())
        {
            pivotIndex = pivotIndex.parent();
        }
        insertRuleToModel(rule, pivotIndex, false);

        pivotRule = rule;
        last++;
    } else
    {
        pivotRule = ruleset->getRuleByNum(pos);
    }

    pivotIndex = index(pivotRule, 0);

    // We need a toplevel index
    if (topLevel && pivotIndex.parent().isValid())
    {
        pivotIndex = pivotIndex.parent();
    }

    for (int i=rules.size()-1; i>=last; i--)
    {
        Rule* rule = rules.at(i);
        ruleset->insert_after(pivotRule, rule);

        insertRuleToModel(rule, pivotIndex, true);

    }
    ruleset->renumberRules();
}

void RuleSetModel::removeRow(int row,const QModelIndex &parent)
{
    removeRows(row,1,parent);
}

bool RuleSetModel::removeRows(int row, int count, const QModelIndex &parent)
{

    if (count < 1 || row < 0 || (row + count > rowCount(parent)))
        return false;

    RuleNode *parentNode = nodeFromIndex(parent);

    int lastRow = row + count - 1;

    beginRemoveRows(parent,row,lastRow);

    for (int i = 0; i<count; i++)
    {

        RuleNode *oldNode = parentNode->children.at(row);

        if (oldNode->type == RuleNode::Group || ruleset->deleteRule(oldNode->rule) )
        {
            parentNode->children.removeAt(row);
            delete oldNode;
        } else {
            //TODO: May be we need some othe action in this case
             qWarning() << "Failed to remove rule";
             break;
        }
    }

    endRemoveRows();
    return true;
}

void RuleSetModel::moveRuleUp(const QModelIndex &group, int first, int last)
{
    RuleNode *groupNode = nodeFromIndex(group);

    if (groupNode->isRoot())
    {
        if (first == 0) return;
        if (root->children.at(first - 1)->type == RuleNode::Group)
        {
            addToGroupAbove(first, last);
            return;
        }
    }
    else
    {
        if (first == 0)
        {
            removeFromGroup(group, first, last);
            return;
        }
    }

    int pos = first - 1;

    QList<RuleNode*> list;
    removeToList(list, group, first, last);

    for(int i = 0; i< list.size(); i++)
    {
        ruleset->moveRuleUp(list.at(i)->rule->getPosition());
    }

    insertFromList(list, group, pos);
}

void RuleSetModel::moveRuleDown(const QModelIndex &group, int first, int last)
{
    RuleNode *groupNode = nodeFromIndex(group);

    int childrens = groupNode->children.size();

    if (groupNode->isRoot())
    {
        if (last == childrens - 1) return;
        if (root->children.at(last + 1)->type == RuleNode::Group)
        {
            addToGroupBelow(first, last);
            return;
        }
    }
    else
    {
        if (last == childrens - 1)
        {
            removeFromGroup(group, first, last);
            return;
        }
    }

    int pos = first + 1;

    QList<RuleNode*> list;
    removeToList(list, group, first, last);

    for(int i = list.size() - 1; i>=0 ; i--)
    {
        ruleset->moveRuleDown(list.at(i)->rule->getPosition());
    }

    insertFromList(list, group, pos);
}

void RuleSetModel::removeToList(QList<RuleNode*> &list, const QModelIndex &group, int first, int last)
{
    emit beginRemoveRows(group, first, last);

    int count = last - first + 1;

    RuleNode *parent = nodeFromIndex(group);

    for (int i=0; i<count; i++)
    {
        list << parent->children.at(first);
        parent->children.removeAt(first);
    }

    emit endRemoveRows();
}

void RuleSetModel::insertFromList(const QList<RuleNode*> &list, const QModelIndex &group, int position)
{
    int first = position;
    int last = position + list.size() - 1;

    emit beginInsertRows(group, first, last);

    RuleNode *parent = nodeFromIndex(group);
    for (int i=list.size()-1; i>=0; i--)
    {
        parent->children.insert(position, list.at(i));
    }

    emit endInsertRows();
}

bool RuleSetModel::isIndexRule(const QModelIndex index)
{
    if (!index.isValid()) return false;
    RuleNode* node = static_cast<RuleNode *>(index.internalPointer());
    if (node == 0) return false;
    return node->type == RuleNode::Rule;
}

void RuleSetModel::changeRuleColor(const QList<QModelIndex> &indexes, const QString &c)
{
    QModelIndex i1 = index(indexes.first().row(), 0, indexes.first().parent());
    QModelIndex i2 = index(indexes.last().row(), header.size() - 1, indexes.last().parent());

    foreach(QModelIndex index, indexes)
    {
        if (!index.isValid()) return;
        RuleNode* node = nodeFromIndex(index);
        if (node->rule==0) return;
        FWOptions *ropt = node->rule->getOptionsObject();
        ropt->setStr("color", c.toLatin1().constData());
    }
    emit dataChanged(i1, i2);
}

void RuleSetModel::changeGroupColor(const QModelIndex index, const QString &c)
{
    if (!index.isValid()) return;
    RuleNode* group = nodeFromIndex(index);
    if (group->type != RuleNode::Group) return;

    foreach (RuleNode* node, group->children)
    {
        if (node->rule==0) continue;
        FWOptions *ropt = node->rule->getOptionsObject();
        ropt->setStr("color", c.toLatin1().constData());
    }
    groupChanged(index);
}

void RuleSetModel::renameGroup(QModelIndex group, const QString &newName)
{
    QString newGroupName = findUniqueNameForGroup(newName);
    RuleNode* groupNode = nodeFromIndex(group);

    //Set new group name for all children of this node.

    foreach (RuleNode* node, groupNode->children)
    {
        node->rule->setRuleGroupName(newGroupName.toUtf8().data());
    }
    groupNode->name = newGroupName;

    rowChanged(group);
}

void RuleSetModel::rowChanged(const QModelIndex &index)
{
    nodeFromIndex(index)->resetSizes();
    emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), header.size()-1,index.internalPointer()));
}

void RuleSetModel::groupChanged(const QModelIndex &group)
{
    RuleNode* groupNode = nodeFromIndex(group);
    QModelIndex i1 = index(0,0,group);
    QModelIndex i2 = index(groupNode->children.size() - 1, header.size()-1, group);
    emit dataChanged(i1, i2);
}

QString RuleSetModel::findUniqueNameForGroup(const QString &groupName)
{
    int count = 0;

    bool exactNameExists = false;

    QRegExp rx("^(.*)-(\\d+)$");

    foreach (RuleNode *node, root->children)
    {
        if (node->type != RuleNode::Group) continue;

        QString name = node->name;

        exactNameExists = exactNameExists || (name == groupName);

        if (rx.exactMatch(name))
        {
            QString nameSection = rx.capturedTexts().at(1);
            QString countSection = rx.capturedTexts().at(2);

            int curCnt = countSection.toInt();

            if (nameSection == groupName && curCnt>count)
                count = curCnt;
        }

    }

    QString uniqueGroupName = (exactNameExists)? groupName + "-" + QString::number(++count):groupName;

    return uniqueGroupName;
}

QModelIndex RuleSetModel::createNewGroup(QString groupName, int first, int last)
{
    QString uniqueGroupName = findUniqueNameForGroup(groupName);

    RuleNode *group = new RuleNode(RuleNode::Group, uniqueGroupName);

     // remove selected rules

    emit beginRemoveRows(QModelIndex(), first, last);
    int count = last - first + 1;
    for(int i=0; i<count; i++)
    {
        RuleNode *node = root->children.at(first);
        group->add(node);
        root->children.removeAt(first);
        node->rule->setRuleGroupName(uniqueGroupName.toUtf8().data());
    }
    emit endRemoveRows();

    // Add new group after the selected rules

    int groupPos = first;
    emit beginInsertRows(QModelIndex(), groupPos, groupPos);
    root->insert(groupPos, group);
    emit endInsertRows();

    return index(groupPos, 0, QModelIndex());

}

void RuleSetModel::removeFromGroup(QModelIndex group, int first, int last)
{
    if (!group.isValid()) return;
    RuleNode *groupNode = nodeFromIndex(group);
    if (groupNode->type != RuleNode::Group) return;

    /*
        if items touch bottom of the group or we are going to move all items from the group
        then we will insert them after the group node one level up, Else we will insert them before\
        the group node.
    */

    int count = last-first+1;
    bool moveAllItems = count == groupNode->children.size();
    bool insertBefore = first == 0;
    int insertPosition = (insertBefore || moveAllItems)?group.row():(group.row()+1);

    // Remove nodes from the tree

    emit beginRemoveRows(group, first, last);

    QList<RuleNode*> moving;
    for(int i = first; i<= last; i++)
    {
        RuleNode *node = groupNode->children.at(first);
        node->rule->setRuleGroupName("");
        moving << node;;
        groupNode->children.removeAt(first);
    }

    emit endRemoveRows();

    QModelIndex rootIndex = group.parent();

    // if all Items were moved from the group then group should be removed as well

    if (moveAllItems)
    {
        emit  beginRemoveRows(rootIndex, group.row(), group.row());
        root->children.removeAt(group.row());
        delete groupNode;
        emit endRemoveRows();
    }

    emit beginInsertRows(rootIndex, insertPosition, insertPosition + count -1);

    // Insert rows to calculated position.

    int pos = insertPosition;

    for(int i=0; i<count; i++)
    {
        root->insert(pos++,moving.at(i));
    }
    emit endInsertRows();
}

QString RuleSetModel::addToGroupAbove(int first, int last)
{
    RuleNode *targetGroup = root->children.at(first - 1);
    moveToGroup(targetGroup, first, last);
    return targetGroup->name;
}

QString RuleSetModel::addToGroupBelow(int first, int last)
{
    RuleNode *targetGroup = root->children.at(last + 1);
    moveToGroup(targetGroup, first, last, false);
    return targetGroup->name;
}

void RuleSetModel::moveToGroup(RuleNode *targetGroup, int first, int last, bool append)
{
    // Remove nodes from the tree
    QList<RuleNode*> rules;
    emit beginRemoveRows(QModelIndex(), first, last);
    int count = last - first + 1;
    for(int i=0; i<count; i++)
    {
        RuleNode *node = root->children.at(first);
        rules << node;
        root->children.removeAt(first);
        node->rule->setRuleGroupName(targetGroup->name.toUtf8().data());
    }
    emit endRemoveRows();

    // Add rules to the group

    int row = (append)?first - 1:first;
    QModelIndex targetGroupIndex = createIndex(row, 0, targetGroup);;
    emit beginInsertRows(targetGroupIndex,
                         (append)?targetGroup->children.size():0,
                         (append)?(targetGroup->children.size()+count-1):(count-1)
                         );

    for(int i=0; i<count; i++)
    {
        if (append)
            targetGroup->add(rules.at(i));
        else
            targetGroup->prepend(rules.at(count - i - 1));
    }
    emit endInsertRows();
}

void RuleSetModel::setEnabled(const QModelIndex &index, bool flag)
{
    if (!index.isValid()) return;
    RuleNode *node = nodeFromIndex(index);
    if (node->type != RuleNode::Rule) return;

    if (flag)
        node->rule->enable();
    else
        node->rule->disable();

    rowChanged(index);
}

void RuleSetModel::deleteObject(QModelIndex &index, FWObject* obj)
{
    RuleElement *re = (RuleElement *)index.data(Qt::DisplayRole).value<void *>();

    if (re==nullptr || re->isAny()) return;

    re->removeRef(obj);

    if (re->isAny()) re->setNeg(false);
    rowChanged(index);

}

bool RuleSetModel::insertObject(QModelIndex &index, FWObject *obj)
{

    ColDesc colDesc = index.data(Qt::UserRole).value<ColDesc>();
    if (colDesc.type != ColDesc::Object && colDesc.type != ColDesc::Time) return false;

    RuleElement *re = (RuleElement *)index.data(Qt::DisplayRole).value<void *>();
    assert (re!=nullptr);

    if (! re->validateChild(obj) )
    {
        if (RuleElementRItf::cast(re))
        {
            QMessageBox::information(
                nullptr , "Firewall Builder",
                QObject::tr(
                    "A single interface belonging to "
                    "this firewall is expected in this field."),
                QString(),QString());
        }
        else if (RuleElementRGtw::cast(re))
        {
            QMessageBox::information(
                nullptr , "Firewall Builder",
                QObject::tr(
                    "A single ip address is expected "
                    "here. You may also insert a host "
                    "or a network adapter leading to "
                    "a single ip adress."),
                QString(),QString());
        }
        return false;
    }

    if (re->getAnyElementId()==obj->getId()) return false;

    if ( !re->isAny())
    {
        /* avoid duplicates */
        int cp_id = obj->getId();
        list<FWObject*>::iterator j;
        for(j=re->begin(); j!=re->end(); ++j)
        {
            FWObject *o=*j;
            if(cp_id==o->getId()) return false;

            FWReference *ref;
            if( (ref=FWReference::cast(o))!=nullptr &&
                 cp_id==ref->getPointerId()) return false;
        }
    }

    re->addRef(obj);

    rowChanged(index);

    return true;
}

void RuleSetModel::getGroups(QList<QModelIndex> &list)
{
    list.clear();
    int row = 0;
    foreach(RuleNode *node, root->children)
    {
        if (node->type == RuleNode::Group)
        {
            list.append(createIndex(row, 0, node));
        }
        row++;
    }
}

RuleSetModelIterator RuleSetModel::begin()
{
    RuleSetModelIterator it;
    if (root->children.isEmpty()) return it;
    it.model = this;
    it.row = 0;
    return it;
}
RuleSetModelIterator RuleSetModel::end()
{
    RuleSetModelIterator it;
    if (root->children.isEmpty()) return it;
    it.model = this;
    it.row = root->children.size();

    return it;
}

bool RuleSetModel::isGroup(const QModelIndex &index) const
{
    RuleNode* node = nodeFromIndex(index);

    return node != nullptr && node->type == RuleNode::Group;
}

void RuleSetModel::resetAllSizes()
{
    emit layoutAboutToBeChanged ();
    root->resetAllSizes();
    emit layoutChanged ();
}

QString RuleSetModel::getPositionAsString(RuleNode *node) const
{
    return QString::number(node->rule->getPosition());
}

ActionDesc RuleSetModel::getRuleActionDesc(Rule* r) const
{
    ActionDesc res;
    res.name = getRuleAction(r);
    Firewall *f = getFirewall();
    if (f)
    {
        res.displayName = getActionNameForPlatform(f, r);
        res.tooltip = FWObjectPropertiesFactory::getRuleActionPropertiesRich(r);
    } else
    {
        res.displayName = res.name;
        res.tooltip = "";
    }

    res.argument = FWObjectPropertiesFactory::getRuleActionProperties(r);

    return res;
}

int RuleSetModel::getRulePosition(QModelIndex index)
{
    Rule* rule = 0;
    if (index.isValid())
    {
        rule = nodeFromIndex(index)->rule;
    }
    return (rule == 0)?0:rule->getPosition();
}

void RuleSetModel::objectChanged(FWObject* object)
{
    Q_UNUSED(object)
/*
 * See #2373
 *
 * Signal dataChanged() is connected to the slot
 * RuleSetView::updateAllColumnsSize() that just calls resizeColumns()
 * and does not do anything different depending on the model
 * index. Can just call it once using different signal.

    QModelIndexList relatedIndexes = findObject(object);

    if (fwbdebug)
        qDebug() << "RuleSetModel::objectChanged"
                 << "object=" << object->getName().c_str()
                 << "relatedIndexes.size()=" << relatedIndexes.size();

    foreach(QModelIndex index, relatedIndexes)
    {
        emit dataChanged(index, index);
    }
*/
    emit layoutChanged();
}

QModelIndexList RuleSetModel::findObject(FWObject* object)
{
    QModelIndexList list;

    RuleSetModelIterator it = begin();
    RuleSetModelIterator end = this->end();

    while (it != end)
    {
        QModelIndex index = it.index();
        RuleNode* node = nodeFromIndex(index);

        if (node->type == RuleNode::Group)
        {
            ++it;
            continue;
        }

        Rule* rule = node->rule;

        // iterate through columns
        int column = 0;
        foreach(ColDesc colDesc, header)
        {
            column++;

            if (colDesc.type == ColDesc::Object || colDesc.type == ColDesc::Time)
            {
                // try to find the object
                RuleElement* re = getRuleElementByRole(
                    rule, colDesc.origin.toStdString());
                if (re->isAny()) continue;

                for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
                {
                    FWObject *obj= *i;
                    if (FWReference::cast(obj)!=nullptr)
                        obj=FWReference::cast(obj)->getPointer();
                    if (obj==nullptr)
                        continue ;
                    if (object == obj)
                    {
                        list.append(this->index(rule, re));
                        break;
                    }
                }
            } else if (colDesc.type == ColDesc::Action)
            {
                PolicyRule * pr = PolicyRule::cast(rule);

                if (pr != 0)
                {
                    if (pr->getAction() == PolicyRule::Branch)
                    {
                        if (pr->getBranch() == object)
                        {
                            list.append(this->index(rule, column));
                        }
                    } else if (pr->getTagging())
                    {
                        if (pr->getTagObject() == object)
                        {
                            list.append(this->index(rule, column));
                        }
                    }
                }
            }

        }
        ++it;
    }

    return list;
}

void RuleSetModel::copyRuleWithoutId(Rule* fromRule, Rule* toRule)
{
    if (fromRule!=nullptr && toRule!=nullptr)
    {
        int oldPos = toRule->getPosition();
        toRule->duplicate(fromRule);
        toRule->setPosition(oldPos);
    }
}

// PolicyModel

void PolicyModel::configure()
{
    supports_logging      = false;
    supports_rule_options = false;
    supports_time         = false;

    string platform;

    if (getFirewall())
    {
        platform = getFirewall()->getStr("platform");

        try {
            supports_logging = Resources::getTargetCapabilityBool(
                    platform, "logging_in_policy");
            supports_rule_options = Resources::getTargetCapabilityBool(
                    platform, "options_in_policy");
            supports_time = Resources::getTargetCapabilityBool(
                    platform, "supports_time");
        } catch(FWException &ex)    {    }
    }

    header  << ColDesc(platform, RuleElementSrc::TYPENAME, ColDesc::Object)   // 1
            << ColDesc(platform, RuleElementDst::TYPENAME, ColDesc::Object)   // 2
            << ColDesc(platform, RuleElementSrv::TYPENAME, ColDesc::Object)   // 3
            << ColDesc(platform, RuleElementItf::TYPENAME, ColDesc::Object)   // 4
            << ColDesc(platform, "Direction", ColDesc::Direction)             // 5
            << ColDesc(platform, "Action", ColDesc::Action);                  // 6
    if (supports_time)
        header << ColDesc(platform, RuleElementInterval::TYPENAME, ColDesc::Time);  // 7

    if (supports_logging && supports_rule_options)
        header << ColDesc(platform, "Options", ColDesc::Options);

    header << ColDesc(platform, "Comment", ColDesc::Comment);
}

QVariant PolicyModel::getRuleDataForDisplayRole(const QModelIndex &index, RuleNode* node) const
{
    QVariant res;

    QTime t;

    if (index.column() == 0)
    {
        res.setValue(getPositionAsString(node));
    } else if (index.column() <= header.size())
    {
        int idx = index.column()-1;
        switch (header[idx].type)
        {
            case ColDesc::Action :
                res.setValue<ActionDesc>(getRuleActionDesc(node->rule));
                break;

            case ColDesc::Direction :
                res.setValue<QString>(getRuleDirection(node->rule));
                break;

            case ColDesc::Options :
                res.setValue<QStringList>(getRuleOptions(node->rule));
                break;

            case ColDesc::Comment :
                res.setValue<QString>(QString::fromUtf8(node->rule->getComment().c_str()));
                break;

            default :
                res.setValue<void *>(getRuleElementByRole(node->rule, header[idx].origin.toStdString()));
        }
    }
    return res;
}

QString PolicyModel::getRuleDirection(Rule* r) const
{
    PolicyRule *policyRule = PolicyRule::cast( r );
    QString dir = policyRule->getDirectionAsString().c_str();
    if (dir.isEmpty() || dir == "Undefined") dir = "Both";
    return dir;
}

QStringList PolicyModel::getRuleOptions(Rule* r) const
{
    QStringList res;
    PolicyRule  *policyRule  = PolicyRule::cast( r );
    FWOptions *ropt = policyRule->getOptionsObject();

    if (policyRule->getLogging()) res << "Log";

    if (!policyRule->getOptionsObject()->getStr("counter_name").empty())
        res << "Accounting";

    if ( ! isDefaultPolicyRuleOptions(r->getOptionsObject())) res << "Options";

    FWObject *firewall = r;
    // use Firewall::cast to match both Firewall and Cluster
    while (!Firewall::cast(firewall)) firewall = firewall->getParent();
    string platform = firewall->getStr("platform");

    if (policyRule->getTagging())
    {
        FWObject *tobj = PolicyRule::cast(policyRule)->getTagObject();
        if (tobj)
        {
            if (platform=="iptables")
            {
                res << tr("Tag %1%2")
                    .arg(QString::fromUtf8(tobj->getName().c_str()))
                    .arg(
                        QString(
                            (ropt->getBool("ipt_mark_connections"))?" (conn)":""));
            } else
                res << tr("Tag %1").arg(
                    QString::fromUtf8(tobj->getName().c_str()));
        }
    }

    if (policyRule->getClassification())
    {
        QString par;

        if (platform=="iptables")
            par = ropt->getStr("classify_str").c_str();

        if (platform=="pf")
            par = ropt->getStr("pf_classify_str").c_str();

        if (platform=="ipfw")
        {
            if (ropt->getInt("ipfw_classify_method") == DUMMYNETPIPE)
            {
                par = "pipe";
            } else {
                par = "queue";
            }
            par = par + " " + ropt->getStr("ipfw_pipe_queue_num").c_str();
        }

        if (!par.isEmpty()) res << tr("Classify %1").arg(par);
    }

    if (policyRule->getRouting())
    {
        res << "Route";
    }

    return res;
}

void PolicyModel::initRule(Rule *new_rule, Rule *old_rule)
{
    PolicyRule *newrule_as_policy_rule = PolicyRule::cast(new_rule);
    if (newrule_as_policy_rule)
    {
        FWOptions *ruleopt = newrule_as_policy_rule->getOptionsObject();
        newrule_as_policy_rule->setLogging(supports_logging &&
                     st->getBool("Objects/PolicyRule/defaultLoggingState"));

        switch (st->getInt("Objects/PolicyRule/defaultAction"))
        {
        case 1:
            newrule_as_policy_rule->setAction(PolicyRule::Accept); break;
        default:
            newrule_as_policy_rule->setAction(PolicyRule::Deny); break;
        }

        switch (st->getInt("Objects/PolicyRule/defaultDirection"))
        {
        case 0:
            newrule_as_policy_rule->setDirection(PolicyRule::Both); break;
        case 1:
            newrule_as_policy_rule->setDirection(PolicyRule::Inbound); break;
        case 2:
            newrule_as_policy_rule->setDirection(PolicyRule::Outbound); break;
        }

        if (st->getInt("Objects/PolicyRule/defaultSource"))
            newrule_as_policy_rule->setDummySource();

        if (st->getInt("Objects/PolicyRule/defaultDestination"))
            newrule_as_policy_rule->setDummyDestination();

        if (st->getInt("Objects/PolicyRule/defaultService"))
            newrule_as_policy_rule->setDummyService();

        if (st->getInt("Objects/PolicyRule/defaultInterface"))
            newrule_as_policy_rule->setDummyInterface();

        ruleopt->setBool("stateless",
                         ! st->getBool("Objects/PolicyRule/defaultStateful") ||
                         getStatelessFlagForAction(newrule_as_policy_rule));
    }

    copyRuleWithoutId(old_rule, new_rule);
}

bool PolicyModel::checkRuleType(libfwbuilder::Rule *rule)
{
    return rule->getTypeName() == PolicyRule::TYPENAME;
}

// NatModel

void NatModel::configure()
{
    supports_actions = false;
    supports_inbound_interface = false;
    supports_outbound_interface = false;

    string platform;

    if (getFirewall())
    {
        platform = getFirewall()->getStr("platform");

    }

    header  << ColDesc(platform, RuleElementOSrc::TYPENAME, ColDesc::Object)   // 1
            << ColDesc(platform, RuleElementODst::TYPENAME, ColDesc::Object)   // 2
            << ColDesc(platform, RuleElementOSrv::TYPENAME, ColDesc::Object)   // 3
            << ColDesc(platform, RuleElementTSrc::TYPENAME, ColDesc::Object)   // 4
            << ColDesc(platform, RuleElementTDst::TYPENAME, ColDesc::Object)   // 5
            << ColDesc(platform, RuleElementTSrv::TYPENAME, ColDesc::Object);   // 6

    if (supports_inbound_interface)
        header << ColDesc(platform, RuleElementItfInb::TYPENAME, ColDesc::Object);
    if (supports_outbound_interface)
        header << ColDesc(platform, RuleElementItfOutb::TYPENAME, ColDesc::Object);

    if (supports_actions)
        header << ColDesc(platform, "Action", ColDesc::Action);

    header << ColDesc(platform, "Options", ColDesc::Options)                  // 7
           << ColDesc(platform, "Comment", ColDesc::Comment);                 // 8
}

QVariant NatModel::getRuleDataForDisplayRole(const QModelIndex &index, RuleNode* node) const
{

    QVariant res;

    if (index.column() == 0)
    {
        res.setValue(getPositionAsString(node));
    } else if (index.column() <= header.size())
    {
        int idx = index.column()-1;
        switch (header[idx].type)
        {
            case ColDesc::Action :
                res.setValue<ActionDesc>(getRuleActionDesc(node->rule));
                break;

            case ColDesc::Options :
                res.setValue<QStringList>(getRuleOptions(node->rule));
                break;

            case ColDesc::Comment :
                res.setValue<QString>(QString::fromUtf8(node->rule->getComment().c_str()));
                break;

            default :
                res.setValue<void *>(getRuleElementByRole(node->rule, header[idx].origin.toStdString()));

        }
    }
    return res;
}

QStringList NatModel::getRuleOptions(Rule* r) const
{
    QStringList res;

    if (!isDefaultNATRuleOptions(r->getOptionsObject())) res << "Options";

    return res;
}

void NatModel::initRule(Rule *new_rule, Rule *old_rule)
{
    NATRule  *natRule = NATRule::cast(new_rule);
    if (natRule)
        natRule->setAction(NATRule::Translate);

    copyRuleWithoutId(old_rule, new_rule);
}

bool NatModel::checkRuleType(libfwbuilder::Rule *rule)
{
    return rule->getTypeName() == NATRule::TYPENAME;
}

// RoutingModel

void RoutingModel::configure()
{
    supports_routing_itf  = false;
    supports_metric  = false;

    string platform;
    string host_os;

    if (getFirewall())
    {
        platform = getFirewall()->getStr("platform");
        host_os = getFirewall()->getStr("host_OS");

        try {
            supports_routing_itf = Resources::getTargetCapabilityBool(
                host_os, "supports_routing_itf");
            supports_metric = Resources::getTargetCapabilityBool(
                host_os, "supports_metric");
        } catch(FWException &ex)    {    }
    }

    header  << ColDesc(platform, RuleElementRDst::TYPENAME, ColDesc::Object)   // 1
            << ColDesc(platform, RuleElementRGtw::TYPENAME, ColDesc::Object);  // 2

    if (supports_routing_itf)
        header << ColDesc(platform, RuleElementRItf::TYPENAME, ColDesc::Object);

    if (supports_metric)
        header  << ColDesc(platform, "Metric", ColDesc::Metric);

    header << ColDesc(platform, "Options", ColDesc::Options)
           << ColDesc(platform, "Comment", ColDesc::Comment);
}

QVariant RoutingModel::getRuleDataForDisplayRole(const QModelIndex &index, RuleNode* node) const
{

    QVariant res;

    if (index.column() == 0)
    {
        res.setValue(getPositionAsString(node));
    } else if (index.column() <= header.size())
    {
        int idx = index.column()-1;
        switch (header[idx].type)
        {
            case ColDesc::Metric :
                res.setValue<QString>(QString::fromUtf8(RoutingRule::cast(node->rule)->getMetricAsString().c_str()));
                break;

            case ColDesc::Options :
                res.setValue<QStringList>(getRuleOptions(node->rule));
                break;

            case ColDesc::Comment :
                res.setValue<QString>(QString::fromUtf8(node->rule->getComment().c_str()));
                break;

            default :
                res.setValue<void *>(getRuleElementByRole(node->rule, header[idx].origin.toStdString()));

        }
    }
    return res;
}

QStringList RoutingModel::getRuleOptions(Rule* r) const
{
    QStringList res;

    if (!isDefaultRoutingRuleOptions(r->getOptionsObject())) res << "Options";

    return res;
}

void RoutingModel::initRule(Rule *new_rule, Rule *old_rule)
{
    copyRuleWithoutId(old_rule, new_rule);
}

bool RoutingModel::checkRuleType(libfwbuilder::Rule *rule)
{
    return rule->getTypeName() == RoutingRule::TYPENAME;
}


try
    {
      TAO::Unknown_IDL_Type *impl = 0;
      ACE_NEW_RETURN (impl,
                      TAO::Unknown_IDL_Type (tc.in ()),
                      false);

      any.replace (impl);
      impl->_tao_decode (cdr);
    }
  catch (const ::CORBA::Exception&)
    {
      return false;
    }

#include "tao/AnyTypeCode/Any.h"
#include "tao/AnyTypeCode/Any_Basic_Impl.h"
#include "tao/AnyTypeCode/Any_Impl_T.h"
#include "tao/AnyTypeCode/Any_Special_Impl_T.h"
#include "tao/AnyTypeCode/Any_Dual_Impl_T.h"
#include "tao/AnyTypeCode/Any_Unknown_IDL_Type.h"
#include "tao/AnyTypeCode/TypeCode.h"
#include "tao/AnyTypeCode/TypeCode_Constants.h"
#include "tao/CDR.h"
#include "tao/SystemException.h"

#include "ace/Log_Msg.h"
#include "ace/OS_NS_string.h"
#include "ace/OS_NS_wchar.h"
#include "ace/OS_Memory.h"
#include <cstring>

#if !defined (__ACE_INLINE__)
# include "tao/AnyTypeCode/Any.inl"
#endif /* ! __ACE_INLINE__ */

TAO_BEGIN_VERSIONED_NAMESPACE_DECL

using namespace TAO;

CORBA::Any::Any ()
  : impl_ (0)
{
}

CORBA::Any::Any (const CORBA::Any &rhs)
  : impl_ (rhs.impl_)
{
  if (this->impl_ != 0)
    {
      this->impl_->_add_ref ();
    }
}

CORBA::Any::~Any ()
{
  if (this->impl_ != 0)
    {
      this->impl_->_remove_ref ();
    }
}

CORBA::Any &
CORBA::Any::operator= (const CORBA::Any &rhs)
{
  if (this->impl_ != rhs.impl_)
    {
      if (this->impl_ != 0)
        {
          this->impl_->_remove_ref ();
        }

      this->impl_ = rhs.impl_;

      if (this->impl_ != 0)
        {
          this->impl_->_add_ref ();
        }
    }

  return *this;
}

void
CORBA::Any::replace (TAO::Any_Impl *new_impl)
{
  ACE_ASSERT (new_impl != 0);

  if (this->impl_ != 0)
    {
      this->impl_->_remove_ref ();
    }

  this->impl_ = new_impl;
}

CORBA::TypeCode_ptr
CORBA::Any::type () const
{
  if (this->impl_ != 0)
    {
      return this->impl_->type ();
    }

  return CORBA::TypeCode::_duplicate (CORBA::_tc_null);
}

CORBA::TypeCode_ptr
CORBA::Any::_tao_get_typecode () const
{
  if (this->impl_ != 0)
    {
      return this->impl_->_tao_get_typecode ();
    }

  return CORBA::_tc_null;
}

void
CORBA::Any::_tao_set_typecode (const CORBA::TypeCode_ptr tc)
{
  if (this->impl_ == 0)
    {
      ACE_NEW (this->impl_,
               TAO::Unknown_IDL_Type (tc));
    }
  else
    {
      this->impl_->type (tc);
    }
}

int
CORBA::Any::_tao_byte_order () const
{
  if (this->impl_ != 0)
    {
      return this->impl_->_tao_byte_order ();
    }

  return TAO_ENCAP_BYTE_ORDER;
}

void
CORBA::Any::type (CORBA::TypeCode_ptr tc)
{
  CORBA::Boolean equiv = false;

  if (this->impl_ != 0)
    {
      equiv = this->impl_->_tao_get_typecode ()->equivalent (tc);
    }

  if (equiv)
    {
      this->impl_->type (tc);
    }
  else
    {
      throw ::CORBA::BAD_TYPECODE ();
    }
}

void
CORBA::Any::_tao_any_destructor (void *x)
{
  CORBA::Any *tmp = static_cast<CORBA::Any *> (x);
  delete tmp;
}

CORBA::Any::to_object::to_object (CORBA::Object_out obj)
  : ref_ (obj.ptr ())
{
}

CORBA::Any::to_abstract_base::to_abstract_base (CORBA::AbstractBase_ptr &obj)
  : ref_ (obj)
{
}

CORBA::Any::to_value::to_value (CORBA::ValueBase *& obj)
  : ref_ (obj)
{
}

CORBA::Boolean
CORBA::Any::checked_to_object (CORBA::Object_ptr &_tao_elem) const
{
  if (this->impl_ == 0)
    {
      return 0;
    }

  return this->impl_->to_object (_tao_elem);
}

CORBA::Boolean
CORBA::Any::checked_to_value (CORBA::ValueBase *&_tao_elem) const
{
  if (this->impl_ == 0)
    {
      return false;
    }

  return this->impl_->to_value (_tao_elem);
}

CORBA::Boolean
CORBA::Any::checked_to_abstract_base (CORBA::AbstractBase_ptr &_tao_elem) const
{
  if (this->impl_ == 0)
    {
      return false;
    }

  return this->impl_->to_abstract_base (_tao_elem);
}

CORBA::Any_var::Any_var (const CORBA::Any_var &r)
  : ptr_ (0)
{
  if (r.ptr_ != 0)
    {
      ACE_NEW (this->ptr_,
               CORBA::Any (*r.ptr_));
    }
}

CORBA::Any_var &
CORBA::Any_var::operator= (CORBA::Any *p)
{
  if (this->ptr_ != p)
    {
      delete this->ptr_;
      this->ptr_ = p;
    }

  return *this;
}

CORBA::Any_var &
CORBA::Any_var::operator= (const CORBA::Any_var &r)
{
  delete this->ptr_;
  this->ptr_ = 0;

  if (r.ptr_ != 0)
    {
      ACE_NEW_RETURN (this->ptr_,
                      CORBA::Any (*r.ptr_),
                      *this);
    }

  return *this;
}

CORBA::Boolean
operator<< (TAO_OutputCDR &cdr, const CORBA::Any &any)
{
  TAO::Any_Impl *impl = any.impl ();

  if (impl != 0)
    {
      return impl->marshal (cdr);
    }

  return (cdr << CORBA::_tc_null);
}

CORBA::Boolean
operator>> (TAO_InputCDR &cdr, CORBA::Any &any)
{
  CORBA::TypeCode_var tc;

  if ((cdr >> tc.out ()) == 0)
    {
      return false;
    }

  return true;
}

#if defined (GEN_OSTREAM_OPS)

std::ostream &
operator<< (std::ostream &strm, const CORBA::Any &)
{
  return strm << "CORBA::Any";
}

#endif /* GEN_OSTREAM_OPS */

// Insertion of the special basic types.

void
CORBA::Any::operator<<= (CORBA::Any::from_boolean b)
{
  TAO::Any_Basic_Impl::insert (*this, CORBA::_tc_boolean, &b.val_);
}

void
CORBA::Any::operator<<= (CORBA::Any::from_octet o)
{
  TAO::Any_Basic_Impl::insert (*this, CORBA::_tc_octet, &o.val_);
}

void
CORBA::Any::operator<<= (CORBA::Any::from_char c)
{
  TAO::Any_Basic_Impl::insert (*this, CORBA::_tc_char, &c.val_);
}

void
CORBA::Any::operator<<= (CORBA::Any::from_wchar wc)
{
  TAO::Any_Basic_Impl::insert (*this, CORBA::_tc_wchar, &wc.val_);
}

void
CORBA::Any::operator<<= (CORBA::Any::from_string s)
{
  if (s.bound_ > 0 && s.val_ != 0 && std::strlen (s.val_) > s.bound_)
    {
      return;
    }

  TAO::Any_Special_Impl_T<
      char,
      CORBA::Any::from_string,
      CORBA::Any::to_string
    >::insert (*this,
               TAO::Any_Impl::_tao_any_string_destructor,
               CORBA::_tc_string,
               s.nocopy_ ? s.val_ : CORBA::string_dup (s.val_),
               s.bound_);
}

void
CORBA::Any::operator<<= (CORBA::Any::from_wstring ws)
{
  if (ws.bound_ > 0 && ws.val_ != 0 && ACE_OS::wslen (ws.val_) > ws.bound_)
    {
      return;
    }

  TAO::Any_Special_Impl_T<
      CORBA::WChar,
      CORBA::Any::from_wstring,
      CORBA::Any::to_wstring
    >::insert (*this,
               TAO::Any_Impl::_tao_any_wstring_destructor,
               CORBA::_tc_wstring,
               ws.nocopy_ ? ws.val_ : CORBA::wstring_dup (ws.val_),
               ws.bound_);
}

// Insertion of the other basic types.

#ifdef ACE_ANY_OPS_USE_NAMESPACE
namespace CORBA
{
#endif

void
operator<<= (CORBA::Any &any, CORBA::Short s)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_short, &s);
}

void
operator<<= (CORBA::Any &any, CORBA::UShort us)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_ushort, &us);
}

void
operator<<= (CORBA::Any &any, CORBA::Long l)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_long, &l);
}

void
operator<<= (CORBA::Any &any, CORBA::ULong ul)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_ulong, &ul);
}

void
operator<<= (CORBA::Any &any, CORBA::LongLong ll)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_longlong, &ll);
}

void
operator<<= (CORBA::Any &any, CORBA::ULongLong ull)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_ulonglong, &ull);
}

void
operator<<= (CORBA::Any &any, CORBA::Float f)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_float, &f);
}

void
operator<<= (CORBA::Any &any, CORBA::Double d)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_double, &d);
}

void
operator<<= (CORBA::Any &any, CORBA::LongDouble ld)
{
  TAO::Any_Basic_Impl::insert (any, CORBA::_tc_longdouble, &ld);
}

// Insertion of Any - copying.
void
operator<<= (CORBA::Any &any, const CORBA::Any &a)
{
  TAO::Any_Dual_Impl_T<CORBA::Any>::insert_copy (
      any,
      CORBA::Any::_tao_any_destructor,
      CORBA::_tc_any,
      a);
}

// Insertion of Any - non-copying.
void
operator<<= (CORBA::Any &any, CORBA::Any *a)
{
  TAO::Any_Dual_Impl_T<CORBA::Any>::insert (any,
                                            CORBA::Any::_tao_any_destructor,
                                            CORBA::_tc_any,
                                            a);
}

// Insertion of TypeCode - copying.
void
operator<<= (CORBA::Any &any, CORBA::TypeCode_ptr tc)
{
  CORBA::TypeCode_ptr dup = CORBA::TypeCode::_duplicate (tc);
  any <<= &dup;
}

// Insertion of TypeCode - non-copying.
void
operator<<= (CORBA::Any &any, CORBA::TypeCode_ptr * tc)
{
  TAO::Any_Impl_T<CORBA::TypeCode>::insert (
      any,
      CORBA::TypeCode::_tao_any_destructor,
      CORBA::_tc_TypeCode,
      *tc);
}

// Insertion of CORBA object - copying.
void
operator<<= (CORBA::Any &any, const CORBA::Object_ptr obj)
{
  CORBA::Object_ptr dup = CORBA::Object::_duplicate (obj);
  any <<= &dup;
}

// Insertion of CORBA object - non-copying.
void
operator<<= (CORBA::Any &any, CORBA::Object_ptr *objptr)
{
  TAO::Any_Impl_T<CORBA::Object>::insert (any,
                                          CORBA::Object::_tao_any_destructor,
                                          CORBA::_tc_Object,
                                          *objptr);
}

// These are copying versions for unbounded (w)strings. They are not inlined,
// to avoid use in Any.inl before definition in ORB.inl.

void
operator<<= (CORBA::Any &any, const char *s)
{
  TAO::Any_Special_Impl_T<
      char,
      CORBA::Any::from_string,
      CORBA::Any::to_string
    >::insert (any,
               TAO::Any_Impl::_tao_any_string_destructor,
               CORBA::_tc_string,
               CORBA::string_dup (s),
               0);
}

void
operator<<= (CORBA::Any &any, const CORBA::WChar *ws)
{
  TAO::Any_Special_Impl_T<
      CORBA::WChar,
      CORBA::Any::from_wstring,
      CORBA::Any::to_wstring
    >::insert (any,
               TAO::Any_Impl::_tao_any_wstring_destructor,
               CORBA::_tc_wstring,
               CORBA::wstring_dup (ws),
               0);
}

void
operator <<= (CORBA::Any &any, const std::string & str)
{
  any <<= str.c_str ();
}

void
operator <<= (CORBA::Any &, std::string *)
{
  // @todo
}

#if !defined(ACE_LACKS_STD_WSTRING)
void
operator <<= (CORBA::Any &any, const std::wstring & str)
{
  any <<= str.c_str ();
}

void
operator <<= (CORBA::Any &, std::wstring *)
{
  // @todo
}
#endif

// Extraction: these are safe and hence we have to check that the
// typecode of the Any is equal to the one we are trying to extract

// Extraction into the special basic types.

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_boolean b) const
{
  return TAO::Any_Basic_Impl::extract (*this, CORBA::_tc_boolean, &b.ref_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_octet o) const
{
  return TAO::Any_Basic_Impl::extract (*this, CORBA::_tc_octet, &o.ref_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_char c) const
{
  return TAO::Any_Basic_Impl::extract (*this, CORBA::_tc_char, &c.ref_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_wchar wc) const
{
  return TAO::Any_Basic_Impl::extract (*this, CORBA::_tc_wchar, &wc.ref_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_string s) const
{
  return
    TAO::Any_Special_Impl_T<
        char,
        CORBA::Any::from_string,
        CORBA::Any::to_string
      >::extract (*this,
                  TAO::Any_Impl::_tao_any_string_destructor,
                  CORBA::_tc_string,
                  s.val_,
                  s.bound_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_wstring ws) const
{
  return
    TAO::Any_Special_Impl_T<
        CORBA::WChar,
        CORBA::Any::from_wstring,
        CORBA::Any::to_wstring
      >::extract (*this,
                  TAO::Any_Impl::_tao_any_wstring_destructor,
                  CORBA::_tc_wstring,
                  ws.val_,
                  ws.bound_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_object obj) const
{
  return this->checked_to_object (obj.ref_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_abstract_base obj) const
{
  return this->checked_to_abstract_base (obj.ref_);
}

CORBA::Boolean
CORBA::Any::operator>>= (CORBA::Any::to_value obj) const
{
  return this->checked_to_value (obj.ref_);
}

// Extraction into the other basic types.

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::Short &s)
{
  return TAO::Any_Basic_Impl::extract (any, CORBA::_tc_short, &s);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::UShort &us)
{
  return TAO::Any_Basic_Impl::extract (any,
                                       CORBA::_tc_ushort,
                                       &us);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::Long &l)
{
  return TAO::Any_Basic_Impl::extract (any,
                                       CORBA::_tc_long,
                                       &l);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::ULong &ul)
{
  return TAO::Any_Basic_Impl::extract (any,
                                       CORBA::_tc_ulong,
                                       &ul);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::LongLong &ll)
{
  return
    TAO::Any_Basic_Impl::extract (any,
                                  CORBA::_tc_longlong,
                                  &ll);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::ULongLong &ull)
{
  return
    TAO::Any_Basic_Impl::extract (any,
                                  CORBA::_tc_ulonglong,
                                  &ull);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::Float &f)
{
  return TAO::Any_Basic_Impl::extract (any,
                                       CORBA::_tc_float,
                                       &f);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::Double &d)
{
  return TAO::Any_Basic_Impl::extract (any,
                                       CORBA::_tc_double,
                                       &d);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::LongDouble &ld)
{
  return
    TAO::Any_Basic_Impl::extract (any,
                                  CORBA::_tc_longdouble,
                                  &ld);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, const CORBA::Any *&a)
{
  return TAO::Any_Dual_Impl_T<CORBA::Any>::extract (
      any,
      CORBA::Any::_tao_any_destructor,
      CORBA::_tc_any,
      a);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, const CORBA::Char *&s)
{
  return
    TAO::Any_Special_Impl_T<
        char,
        CORBA::Any::from_string,
        CORBA::Any::to_string
      >::extract (any,
                  TAO::Any_Impl::_tao_any_string_destructor,
                  CORBA::_tc_string,
                  s,
                  0);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, const CORBA::WChar *&ws)
{
  return
    TAO::Any_Special_Impl_T<
        CORBA::WChar,
        CORBA::Any::from_wstring,
        CORBA::Any::to_wstring
      >::extract (any,
                  TAO::Any_Impl::_tao_any_wstring_destructor,
                  CORBA::_tc_wstring,
                  ws,
                  0);
}

CORBA::Boolean
operator>>= (const CORBA::Any &any, CORBA::TypeCode_ptr &tc)
{
  return TAO::Any_Impl_T<CORBA::TypeCode>::extract (
      any,
      CORBA::TypeCode::_tao_any_destructor,
      CORBA::_tc_TypeCode,
      tc);
}

CORBA::Boolean
operator >>= (const CORBA::Any &any, std::string &str)
{
  const char *buf = 0;
  CORBA::Boolean flag = any >>= buf;

  if (buf != 0)
    {
      str.assign (buf);
    }

  return flag;
}

#if !defined(ACE_LACKS_STD_WSTRING)
CORBA::Boolean
operator >>= (const CORBA::Any &any, std::wstring &str)
{
  const wchar_t *buf = 0;
  CORBA::Boolean flag = any >>= buf;

  if (buf != 0)
    {
      str.assign (buf);
    }

  return flag;
}
#endif

#ifdef ACE_ANY_OPS_USE_NAMESPACE
}
#endif

// Any_Impl_T template specializations.

namespace TAO
{
  template<>
  CORBA::Boolean
  Any_Impl_T<CORBA::Object>::to_object (CORBA::Object_ptr &_tao_elem) const
  {
    _tao_elem = CORBA::Object::_duplicate (this->value_);
    return true;
  }
}

TAO_END_VERSIONED_NAMESPACE_DECL