class VendorDataManager
{
	private var m_VendorObject : weak< GameObject >;
	private var m_BuyingCart : array< VendorShoppingCartItem >;
	private var m_SellingCart : array< VendorShoppingCartItem >;
	private var m_VendorID : TweakDBID;
	private var m_VendingBlacklist : array< EVendorMode >;
	private var m_TimeToCompletePurchase : Float;
	protected var m_UIBBEquipment : UI_EquipmentDef;
	private var m_InventoryBBID : CallbackHandle;
	private var m_EquipmentBBID : CallbackHandle;
	private var m_openTime : GameTime;

	public function Initialize( vendor : weak< GameObject >, const vendingTerminalSetup : ref< VendingTerminalSetup > )
	{
		m_VendorObject = vendor;
		m_VendorID = vendingTerminalSetup.m_vendorTweakID;
		m_VendingBlacklist = vendingTerminalSetup.m_vendingBlacklist;
		m_TimeToCompletePurchase = vendingTerminalSetup.m_timeToCompletePurchase;
		MarketSystem.OnVendorMenuOpen( m_VendorObject );
	}

	public function Initialize( owner : weak< GameObject >, entityID : EntityID )
	{
		m_TimeToCompletePurchase = 0.0;
		m_VendorObject = ( ( GameObject )( GameInstance.FindEntityByID( owner.GetGame(), entityID ) ) );
		m_VendorID = MarketSystem.GetVendorID( m_VendorObject );
		MarketSystem.OnVendorMenuOpen( m_VendorObject );
	}

	public function UpdateOpenTime( gameInstance : GameInstance )
	{
		m_openTime = GameInstance.GetTimeSystem( gameInstance ).GetGameTime();
	}

	public function GetOpenTime() : GameTime
	{
		return m_openTime;
	}

	public function GetVendorInstance() : weak< GameObject >
	{
		return m_VendorObject;
	}

	public function GetVendorID() : TweakDBID
	{
		return m_VendorID;
	}

	public function GetLocalPlayer() : weak< PlayerPuppet >
	{
		return VendorDataManager.GetLocalPlayer( m_VendorObject.GetGame() );
	}

	public static function GetLocalPlayer( game : GameInstance ) : weak< PlayerPuppet >
	{
		return ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( game ).GetLocalPlayerMainGameObject() ) );
	}

	public function GetVendorRecord() : weak< Vendor_Record >
	{
		return TweakDBInterface.GetVendorRecord( m_VendorID );
	}

	public function GetVendorName() : String
	{
		return TweakDBInterface.GetVendorRecord( m_VendorID ).LocalizedName();
	}

	public function GetVendorDescription() : String
	{
		return TweakDBInterface.GetVendorRecord( m_VendorID ).LocalizedDescription();
	}

	public function GetLocalPlayerCurrencyAmount() : Int32
	{
		return GetLocalPlayerCurrencyAmount( GetLocalPlayer() );
	}

	public static function GetLocalPlayerCurrencyAmount( player : weak< GameObject > ) : Int32
	{
		return GameInstance.GetTransactionSystem( player.GetGame() ).GetItemQuantity( player, MarketSystem.Money() );
	}

	public function GetVendorInventoryItems() : array< VendorGameItemData >
	{
		var vendorStock : array< SItemStack >;
		var transactionSys : TransactionSystem;
		var itemData : gameItemData;
		var vendorItemData : VendorGameItemData;
		var i : Int32;
		var inventory : array< VendorGameItemData >;
		transactionSys = GameInstance.GetTransactionSystem( m_VendorObject.GetGame() );
		vendorStock = MarketSystem.GetVendorItemsForSale( m_VendorObject, true );
		for( i = 0; i < vendorStock.Size(); i += 1 )
		{
			vendorItemData = new VendorGameItemData;
			itemData = transactionSys.GetItemData( m_VendorObject, vendorStock[ i ].itemID );
			if( !( itemData ) )
			{
				continue;
			}
			vendorItemData.gameItemData = itemData;
			vendorItemData.itemStack = vendorStock[ i ];
			inventory.PushBack( vendorItemData );
		}
		return inventory;
	}

	public function GetVendorSoldItems() : SoldItemsCache
	{
		return MarketSystem.GetVendorSoldItems( m_VendorObject );
	}

	public function GetRipperDocItems() : array< VendorGameItemData >
	{
		var cyberwareStock : array< SItemStack >;
		var transactionSys : TransactionSystem;
		var itemData : gameItemData;
		var vendorItemData : VendorGameItemData;
		var i : Int32;
		var inventory : array< VendorGameItemData >;
		transactionSys = GameInstance.GetTransactionSystem( m_VendorObject.GetGame() );
		cyberwareStock = MarketSystem.GetVendorCyberwareForSale( m_VendorObject, true );
		for( i = 0; i < cyberwareStock.Size(); i += 1 )
		{
			vendorItemData = new VendorGameItemData;
			itemData = transactionSys.GetItemData( m_VendorObject, cyberwareStock[ i ].itemID );
			vendorItemData.gameItemData = itemData;
			vendorItemData.itemStack = cyberwareStock[ i ];
			inventory.PushBack( vendorItemData );
		}
		return inventory;
	}

	public function GetItemsPlayerCanSell() : array< gameItemData >
	{
		var playerStock : array< SItemStack >;
		var transactionSys : TransactionSystem;
		var itemData : gameItemData;
		var i : Int32;
		var sellItemData : array< gameItemData >;
		transactionSys = GameInstance.GetTransactionSystem( m_VendorObject.GetGame() );
		playerStock = MarketSystem.GetItemsPlayerCanSell( m_VendorObject, false, false );
		for( i = 0; i < playerStock.Size(); i += 1 )
		{
			itemData = transactionSys.GetItemData( GetPlayer( m_VendorObject.GetGame() ), playerStock[ i ].itemID );
			sellItemData.PushBack( itemData );
		}
		return sellItemData;
	}

	public function ArePlayerQuestItemsHidden() : Bool
	{
		var tagsToFilterOut : array< CName >;
		tagsToFilterOut = GetVendorRecord().CustomerFilterTags();
		return tagsToFilterOut.Contains( 'Quest' );
	}

	public function GetItemsPlayerCanSellFast( player : weak< GameObject >, optional excludeEquipped : Bool ) : array< weak< gameItemData > >
	{
		var result : array< weak< gameItemData > >;
		var i : Int32;
		var vendorRecord : weak< Vendor_Record >;
		var transactionSystem : TransactionSystem;
		var equipmentSystem : EquipmentSystem;
		var requiredTags, tagsToFilterOut : array< CName >;
		vendorRecord = GetVendorRecord();
		tagsToFilterOut = vendorRecord.CustomerFilterTags();
		requiredTags = vendorRecord.CustomerInverseFilterTags();
		transactionSystem = GameInstance.GetTransactionSystem( player.GetGame() );
		transactionSystem.GetItemListFilteredByTags( player, requiredTags, tagsToFilterOut, result );
		if( excludeEquipped )
		{
			equipmentSystem = EquipmentSystem.GetInstance( player );
			for( i = result.Size() - 1; i >= 0; i -= 1 )
			{
				if( equipmentSystem.IsEquipped( player, result[ i ].GetID() ) )
				{
					result.EraseFast( i );
				}
			}
		}
		return result;
	}

	public function CanPlayerSellItem( itemID : ItemID ) : Bool
	{
		return MarketSystem.CanPlayerSellItem( m_VendorObject, itemID, false, false );
	}

	public function GetStorageItems() : array< gameItemData >
	{
		var transactionSys : TransactionSystem;
		var itemList : array< weak< gameItemData > >;
		var gameItemList : array< gameItemData >;
		var i : Int32;
		transactionSys = GameInstance.GetTransactionSystem( m_VendorObject.GetGame() );
		transactionSys.GetItemList( m_VendorObject, itemList );
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			gameItemList.PushBack( ( ( gameItemData )( itemList[ i ] ) ) );
		}
		return gameItemList;
	}

	public function BuyItemFromVendor( itemData : weak< gameItemData >, amount : Int32, optional requestId : Int32 )
	{
		var buyRequest : BuyRequest;
		var buyRequestData : TransactionRequestData;
		var uiSys : UISystem;
		var evt : VendorBoughtItemEvent;
		uiSys = GameInstance.GetUISystem( m_VendorObject.GetGame() );
		evt = new VendorBoughtItemEvent;
		evt.items.PushBack( itemData.GetID() );
		uiSys.QueueEvent( evt );
		buyRequestData.itemID = itemData.GetID();
		buyRequestData.quantity = amount;
		buyRequest = new BuyRequest;
		buyRequest.owner = m_VendorObject;
		buyRequest.requestID = requestId;
		buyRequest.items.PushBack( buyRequestData );
		MarketSystem.GetInstance( m_VendorObject.GetGame() ).QueueRequest( buyRequest );
	}

	public function BuybackItemFromVendor( itemData : weak< gameItemData >, amount : Int32, optional requestId : Int32 )
	{
		var buybackRequest : BuybackRequest;
		var buybackRequestData : TransactionRequestData;
		var uiSys : UISystem;
		var evt : VendorBoughtItemEvent;
		uiSys = GameInstance.GetUISystem( m_VendorObject.GetGame() );
		evt = new VendorBoughtItemEvent;
		evt.items.PushBack( itemData.GetID() );
		uiSys.QueueEvent( evt );
		buybackRequestData.itemID = itemData.GetID();
		buybackRequestData.quantity = amount;
		buybackRequest = new BuybackRequest;
		buybackRequest.owner = m_VendorObject;
		buybackRequest.requestID = requestId;
		buybackRequest.items.PushBack( buybackRequestData );
		MarketSystem.GetInstance( m_VendorObject.GetGame() ).QueueRequest( buybackRequest );
	}

	public function SellItemToVendor( itemData : weak< gameItemData >, amount : Int32, optional requestId : Int32 )
	{
		var itemsData : array< weak< gameItemData > >;
		var amounts : array< Int32 >;
		itemsData.PushBack( itemData );
		amounts.PushBack( amount );
		SellItemsToVendor( itemsData, amounts, requestId );
	}

	public function SellItemsToVendor( const itemsData : ref< array< weak< gameItemData > > >, const amounts : ref< array< Int32 > >, optional requestId : Int32 )
	{
		var sellRequest : SellRequest;
		var sellRequestData : TransactionRequestData;
		var i, limit : Int32;
		sellRequest = new SellRequest;
		sellRequest.owner = m_VendorObject;
		sellRequest.requestID = requestId;
		for( i = 0, limit = itemsData.Size(); i < limit; i += 1 )
		{
			sellRequestData.itemID = itemsData[ i ].GetID();
			sellRequestData.quantity = amounts[ i ];
			sellRequestData.powerLevel = itemsData[ i ].GetStatValueByType( gamedataStatType.PowerLevel );
			sellRequest.items.PushBack( sellRequestData );
		}
		MarketSystem.GetInstance( m_VendorObject.GetGame() ).QueueRequest( sellRequest );
	}

	public function TransferItem( source : weak< GameObject >, target : weak< GameObject >, itemData : weak< gameItemData >, amount : Int32 )
	{
		var transactionSys : TransactionSystem;
		transactionSys = GameInstance.GetTransactionSystem( m_VendorObject.GetGame() );
		transactionSys.TransferItem( source, target, itemData.GetID(), amount );
	}

	public function GetBuyingPrice( itemID : ItemID ) : Int32
	{
		return MarketSystem.GetBuyPrice( m_VendorObject, itemID );
	}

	public function GetSellingPrice( itemID : ItemID ) : Int32
	{
		return RPGManager.CalculateSellPrice( m_VendorObject.GetGame(), m_VendorObject, itemID );
	}

	public function Checkout( andEquip : Bool ) : Bool
	{
		var itemsToBuy, itemsToSell : array< ItemID >;
		GetItemIDsFromCart( itemsToBuy, m_BuyingCart );
		GetItemIDsFromCart( itemsToSell, m_SellingCart );
		ClearBuyingCart();
		ClearSellingCart();
		return false;
	}

	public function ClearCart()
	{
		ClearBuyingCart();
		ClearSellingCart();
	}

	private function ClearBuyingCart()
	{
		var i : Int32;
		for( i = 0; i < m_BuyingCart.Size(); i += 1 )
		{
			BuyItemFromVendor( m_BuyingCart[ i ].itemData, m_BuyingCart[ i ].amount );
		}
		m_BuyingCart.Clear();
	}

	private function ClearSellingCart()
	{
		var i : Int32;
		for( i = 0; i < m_SellingCart.Size(); i += 1 )
		{
			SellItemToVendor( m_SellingCart[ i ].itemData, m_SellingCart[ i ].amount );
		}
		m_SellingCart.Clear();
	}

	public function NumItemsInBuyingCart() : Int32
	{
		return m_BuyingCart.Size();
	}

	public function NumItemsInSellingCart() : Int32
	{
		return m_SellingCart.Size();
	}

	public function NumItemsInAllCarts() : Int32
	{
		return NumItemsInBuyingCart() + NumItemsInSellingCart();
	}

	public function TotalNumItemsInAllCarts() : Int32
	{
		return GetTotalAmountInCart( m_BuyingCart ) + GetTotalAmountInCart( m_SellingCart );
	}

	public function AddToBuyingCart( itemToAdd : weak< gameItemData > ) : ECartOperationResult
	{
		var returnValue : ECartOperationResult;
		returnValue = CanAddToBuyingCart( itemToAdd );
		if( returnValue == ECartOperationResult.Success )
		{
			AddToCart( itemToAdd, m_BuyingCart );
		}
		return returnValue;
	}

	public function AddToSellingCart( itemToAdd : weak< gameItemData > ) : ECartOperationResult
	{
		var returnValue : ECartOperationResult;
		returnValue = CanAddToSellingCart( itemToAdd );
		if( returnValue == ECartOperationResult.Success )
		{
			AddToCart( itemToAdd, m_SellingCart );
		}
		return returnValue;
	}

	public function RemoveFromBuyingCart( itemToRemove : weak< gameItemData > ) : ECartOperationResult
	{
		if( RemoveFromCart( itemToRemove, m_BuyingCart ) )
		{
			return ECartOperationResult.Success;
		}
		return ECartOperationResult.NotInCart;
	}

	public function RemoveFromSellingCart( itemToRemove : weak< gameItemData > ) : ECartOperationResult
	{
		if( RemoveFromCart( itemToRemove, m_SellingCart ) )
		{
			return ECartOperationResult.Success;
		}
		return ECartOperationResult.NotInCart;
	}

	private function CanAddToBuyingCart( itemToAdd : weak< gameItemData > ) : ECartOperationResult
	{
		var itemQuantity : Int32;
		itemQuantity = itemToAdd.GetQuantity();
		if( itemQuantity == 0 )
		{
			return ECartOperationResult.NoItems;
		}
		if( GetAmountInBuiyngCart( itemToAdd ) >= itemQuantity )
		{
			return ECartOperationResult.AllItems;
		}
		return ECartOperationResult.Success;
	}

	private function CanAddToSellingCart( itemToAdd : weak< gameItemData > ) : ECartOperationResult
	{
		var itemQuantity : Int32;
		itemQuantity = itemToAdd.GetQuantity();
		if( itemQuantity == 0 )
		{
			return ECartOperationResult.NoItems;
		}
		if( GetAmountInSellingCart( itemToAdd ) >= itemQuantity )
		{
			return ECartOperationResult.AllItems;
		}
		if( itemToAdd.HasTag( 'Quest' ) )
		{
			return ECartOperationResult.QuestItem;
		}
		return ECartOperationResult.Success;
	}

	public function GetAmountInBuiyngCart( item : weak< gameItemData > ) : Int32
	{
		return GetAmountInCart( item, m_BuyingCart );
	}

	public function GetAmountInSellingCart( item : weak< gameItemData > ) : Int32
	{
		return GetAmountInCart( item, m_SellingCart );
	}

	public function GetItemDataFromBuyingCart( items : ref< array< weak< gameItemData > > > )
	{
		return GetItemDataFromCart( items, m_BuyingCart );
	}

	public function GetItemDataFromSellingCart( items : ref< array< weak< gameItemData > > > )
	{
		return GetItemDataFromCart( items, m_SellingCart );
	}

	public function GetTimeToCompletePurchase() : Float
	{
		return m_TimeToCompletePurchase;
	}

	public function GetPriceInBuyingCart() : Int32
	{
		var i, limit, price : Int32;
		price = 0;
		for( i = 0, limit = m_BuyingCart.Size(); i < limit; i += 1 )
		{
			price += ( m_BuyingCart[ i ].amount * GetBuyingPrice( m_BuyingCart[ i ].itemData.GetID() ) );
		}
		return price;
	}

	public function GetPriceInSellingCart() : Int32
	{
		var i, limit, price : Int32;
		price = 0;
		for( i = 0, limit = m_SellingCart.Size(); i < limit; i += 1 )
		{
			price += ( m_BuyingCart[ i ].amount * GetSellingPrice( m_SellingCart[ i ].itemData.GetID() ) );
		}
		return price;
	}

	private function AddToCart( itemToAdd : weak< gameItemData >, out cart : array< VendorShoppingCartItem > )
	{
		var i, limit, quantityToAdd : Int32;
		quantityToAdd = itemToAdd.GetQuantity();
		if( quantityToAdd > 0 )
		{
			for( i = 0, limit = cart.Size(); i < limit; i += 1 )
			{
				if( cart[ i ].itemData == itemToAdd )
				{
					if( cart[ i ].amount < quantityToAdd )
					{
						cart[ i ].amount += 1;
						return;
					}
				}
			}
			cart.PushBack( VendorShoppingCartItem( itemToAdd, 1 ) );
		}
	}

	private function RemoveFromCart( itemToAdd : weak< gameItemData >, out cart : array< VendorShoppingCartItem > ) : Bool
	{
		var i, limit : Int32;
		for( i = 0, limit = cart.Size(); i < limit; i += 1 )
		{
			if( cart[ i ].itemData == itemToAdd )
			{
				if( cart[ i ].amount > 0 )
				{
					cart[ i ].amount -= 1;
					if( cart[ i ].amount == 0 )
					{
						cart.Erase( i );
					}
					return true;
				}
				else
				{
					return false;
				}
			}
		}
		return false;
	}

	private function GetTotalAmountInCart( const cart : ref< array< VendorShoppingCartItem > > ) : Int32
	{
		var i, limit : Int32;
		var outValue : Int32;
		outValue = 0;
		for( i = 0, limit = cart.Size(); i < limit; i += 1 )
		{
			outValue += cart[ i ].amount;
		}
		return outValue;
	}

	private function GetAmountInCart( itemToAdd : weak< gameItemData >, const cart : ref< array< VendorShoppingCartItem > > ) : Int32
	{
		var i, limit : Int32;
		for( i = 0, limit = cart.Size(); i < limit; i += 1 )
		{
			if( cart[ i ].itemData == itemToAdd )
			{
				return cart[ i ].amount;
			}
		}
		return 0;
	}

	private function GetItemDataFromCart( items : ref< array< weak< gameItemData > > >, const cart : ref< array< VendorShoppingCartItem > > )
	{
		var i, limit : Int32;
		for( i = 0, limit = cart.Size(); i < limit; i += 1 )
		{
			if( cart[ i ].amount > 0 )
			{
				items.PushBack( cart[ i ].itemData );
			}
		}
	}

	public function GetItemIDsFromCart( itemIds : ref< array< ItemID > >, const cart : ref< array< VendorShoppingCartItem > > )
	{
		var i, limitI, j, limitJ : Int32;
		for( i = 0, limitI = cart.Size(); i < limitI; i += 1 )
		{
			for( j = 0, limitJ = cart[ i ].amount; j < limitJ; j += 1 )
			{
				itemIds.PushBack( cart[ i ].itemData.GetID() );
			}
		}
	}

	public function ProcessTooltipsData( vendorMode : EVendorMode, tooltipsData : ref< array< ATooltipData > > )
	{
		var i, limit : Int32;
		var itemTooltipData : InventoryTooltipData;
		for( i = 0, limit = tooltipsData.Size(); i < limit; i += 1 )
		{
			itemTooltipData = ( ( InventoryTooltipData )( tooltipsData[ i ] ) );
			if( itemTooltipData )
			{
				if( itemTooltipData.isEquipped )
				{
					itemTooltipData.price = 0.0;
				}
				else
				{
					if( vendorMode == EVendorMode.BuyItems )
					{
						itemTooltipData.price = ( ( Float )( GetBuyingPrice( itemTooltipData.itemID ) ) );
					}
					else if( vendorMode == EVendorMode.SellItems )
					{
						itemTooltipData.price = ( ( Float )( GetSellingPrice( itemTooltipData.itemID ) ) );
					}
				}
			}
		}
	}

}

importonly struct VendorData
{
	import var vendorId : String;
	import var entityID : EntityID;
	import var isActive : Bool;
}

importonly class VendorPanelData extends IScriptable
{
	import var assetsLibrary : String;
	import var rootItemName : CName;
	import var data : VendorData;
}

class VendorBoughtItemEvent extends Event
{
	var items : array< ItemID >;
}

struct VendorShoppingCartItem
{
	var itemData : weak< gameItemData >;
	var amount : Int32;
}

enum ECartOperationResult
{
	Success = 0,
	NoItems = 1,
	AllItems = 2,
	WontSell = 3,
	WontBuy = 4,
	QuestItem = 5,
	NotInCart = 6,
}

enum EVendorMode
{
	BuyItems = 0,
	SellItems = 1,
	Train = 2,
	Ripperdoc = 3,
	RipperdocSummary = 4,
}

class VendorGameItemData
{
	var gameItemData : gameItemData;
	var itemStack : SItemStack;
}

