
class StrifeStatusBar : BaseStatusBar
{
	
	// Number of tics to move the popscreen up and down.
	const POP_TIME = (Thinker.TICRATE/8);

	// Popscreen height when fully extended
	const POP_HEIGHT = 104;

	// Number of tics to scroll keys left
	const KEY_TIME = (Thinker.TICRATE/3);

	enum eImg
	{
		imgINVCURS,
		imgCURSOR01,
		imgINVBACK,
		imgINVTOP,
		imgINVPOP,
		imgINVPOP2,
		imgINVPBAK,
		imgINVPBAK2,
		imgFONG0,
		imgFONG1,
		imgFONG2,
		imgFONG3,
		imgFONG4,
		imgFONG5,
		imgFONG6,
		imgFONG7,
		imgFONG8,
		imgFONG9,
		imgFONG_PERCENT,
		imgFONY0,
		imgFONY1,
		imgFONY2,
		imgFONY3,
		imgFONY4,
		imgFONY5,
		imgFONY6,
		imgFONY7,
		imgFONY8,
		imgFONY9,
		imgFONY_PERCENT,
		imgCOMM,
		imgMEDI,
		imgARM1,
		imgARM2,
		imgNEGATIVE,
	};
	
	TextureID Images[imgNEGATIVE + 1];
	int CursorImage;
	int CurrentPop, PendingPop, PopHeight, PopHeightChange;
	int KeyPopPos, KeyPopScroll;
	double ItemFlash;

	override void Init()
	{
		Super.Init();
		SetSize(32, 320, 200);
		DoCommonInit();
	}

	override void NewGame ()
	{
		DoCommonInit ();
		if (CPlayer != NULL)
		{
			AttachToPlayer (CPlayer);
		}
	}

	override void Draw (int state, double TicFrac)
	{
		Super.Draw (state, TicFrac);

		if (state == HUD_StatusBar)
		{
			fullscreenoffsets = false;
			DrawMainBar (TicFrac);
		}
		else
		{
			if (state == HUD_Fullscreen)
			{
				fullscreenoffsets = true;
				DrawFullScreenStuff ();
			}

			// Draw pop screen (log, keys, and status)
			if (CurrentPop != POP_None && PopHeight < 0)
			{
				fullscreenoffsets = false;
				DrawPopScreen (screen.GetHeight(), TicFrac);
			}
		}
	}

	override void ShowPop (int popnum)
	{
		Super.ShowPop(popnum);
		if (popnum == CurrentPop)
		{
			if (popnum == POP_Keys)
			{
				Inventory item;

				KeyPopPos += 10;
				KeyPopScroll = 280;

				int i = 0;
				for (item = CPlayer.mo.Inv; item != NULL; item = item.Inv)
				{
					if (item is "Key")
					{
						if (i == KeyPopPos)
						{
							return;
						}
						i++;
					}
				}
			}
			PendingPop = POP_None;
			// Do not scroll keys horizontally when dropping the popscreen
			KeyPopScroll = 0;
			KeyPopPos -= 10;
		}
		else
		{
			KeyPopPos = 0;
			PendingPop = popnum;
		}
	}

	override bool MustDrawLog(int state)
	{
		// Tell the base class to draw the log if the pop screen won't be displayed.
		return false;
	}

	void DoCommonInit ()
	{
		static const String strifeLumpNames[] =
		{
			"INVCURS", "CURSOR01", "INVBACK", "INVTOP", "INVPOP", "INVPOP2",
			"INVPBAK", "INVPBAK2",
			"INVFONG0", "INVFONG1", "INVFONG2", "INVFONG3", "INVFONG4",
			"INVFONG5", "INVFONG6", "INVFONG7", "INVFONG8", "INVFONG9",
			"INVFONG%",
			"INVFONY0", "INVFONY1", "INVFONY2", "INVFONY3", "INVFONY4",
			"INVFONY5", "INVFONY6", "INVFONY7", "INVFONY8", "INVFONY9",
			"INVFONY%",
			"I_COMM", "I_MDKT", "I_ARM1", "I_ARM2", ""

		};
		
		for(int i = 0; i <= imgNEGATIVE; i++)
		{
			Images[i] = TexMan.CheckForTexture(strifeLumpNames[i], TexMan.TYPE_MiscPatch);
		}

		CursorImage = Images[imgINVCURS].IsValid() ? imgINVCURS : imgCURSOR01;

		CurrentPop = POP_None;
		PendingPop = POP_NoChange;
		PopHeight = 0;
		KeyPopPos = 0;
		KeyPopScroll = 0;
		ItemFlash = 0;
	}

	override void Tick ()
	{
		Super.Tick ();

		if (ItemFlash > 0)
		{
			ItemFlash -= 1/14.;
			if (ItemFlash < 0)
			{
				ItemFlash = 0;
			}
		}

		PopHeightChange = 0;
		if (PendingPop != POP_NoChange)
		{
			if (PopHeight < 0)
			{
				PopHeightChange = POP_HEIGHT / POP_TIME;
				PopHeight += POP_HEIGHT / POP_TIME;
			}
			else
			{
				CurrentPop = PendingPop;
				PendingPop = POP_NoChange;
			}
		}
		else
		{
			if (CurrentPop == POP_None)
			{
				PopHeight = 0;
			}
			else if (PopHeight > -POP_HEIGHT)
			{
				PopHeight -= POP_HEIGHT / POP_TIME;
				if (PopHeight < -POP_HEIGHT)
				{
					PopHeight = -POP_HEIGHT;
				}
				else
				{
					PopHeightChange = -POP_HEIGHT / POP_TIME;
				}
			}
			if (KeyPopScroll > 0)
			{
				KeyPopScroll -= 280 / KEY_TIME;
				if (KeyPopScroll < 0)
				{
					KeyPopScroll = 0;
				}
			}
		}
	}

	override void FlashItem (Class<Inventory> itemtype)
	{
		ItemFlash = 0.75;
	}
	
	private void FillBar(double x, double y, double start, double stopp, Color color1, Color color2)
	{
		Vector2 virt = Scaled? (320., 200.) : (screen.GetWidth(), screen.GetHeight());
		Vector2 pos, sizev;
		
		start *=2;
		stopp *=2;
		
		[pos, sizev] = screen.VirtualToRealCoords((ST_X + x + start, ST_Y + y), (stopp - start, 1), virt, true, Scaled); 
		screen.Dim(color1, 1.0, pos.X + 0.5, pos.Y + 0.5, sizev.X + 0.5, sizev.Y + 0.5);

		[pos, sizev] = screen.VirtualToRealCoords((ST_X + x + start, ST_Y + y + 1), (stopp - start, 1), virt, true, Scaled); 
		screen.Dim(color2, 1.0, pos.X + 0.5, pos.Y + 0.5, sizev.X + 0.5, sizev.Y + 0.5);
	}
	
	protected void DrawHealthBar(int health, int x, int y)
	{
		Color green1 = Color(180, 228, 128);	// light green
		Color green2 = Color(128, 180, 80);		// dark green

		Color blue1 = Color(196, 204, 252);		// light blue
		Color blue2 = Color(148, 152, 200);		// dark blue

		Color gold1 = Color(224, 188, 0);	// light gold
		Color gold2 = Color(208, 128, 0);	// dark gold

		Color red1 = Color(216, 44,  44);	// light red
		Color red2 = Color(172, 28,  28);	// dark red
		
		if (health == 999)
		{
			FillBar (x, y, 0, 100, gold1, gold2);
		}
		else
		{
			if (health <= 100)
			{
				if (health <= 10)
				{
					FillBar (x, y, 0, health, red1, red2);
				}
				else if (health <= 20)
				{
					FillBar (x, y, 0, health, gold1, gold2);
				}
				else
				{
					FillBar (x, y, 0, health, green1, green2);
				}
				//FillBar (x, y, health, 100, 0, 0);
			}
			else
			{
				int stopp = 200 - health;
				FillBar (x, y, 0, stopp, green1, green2);
				FillBar (x, y, stopp, 100, blue1, blue2);
			}
		}
	}

	protected void DrawMainBar (double TicFrac)
	{
		Inventory item;
		int i;

		// Pop screen (log, keys, and status)
		if (CurrentPop != POP_None && PopHeight < 0)
		{
			DrawPopScreen (Scaled ? (ST_Y - 8) * screen.GetHeight() / 200 : ST_Y - 8, TicFrac);
		}

		DrawTexture(Images[imgINVBACK], (0, 0), true, 1.0, itemAlign:ALIGN_OFFSETS);
		DrawTexture(Images[imgINVTOP], (0, -8), true, 1.0, itemAlign:ALIGN_OFFSETS);

		// Health
		DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 5, 0), (86, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
		int points;
		if (CPlayer.cheats & CF_GODMODE)
		{
			points = 999;
		}
		else
		{
			points = min(CPlayer.health, 200);
		}
		DrawHealthBar (points, 49, 4);
		DrawHealthBar (points, 49, 7);

		// Armor
		item = CPlayer.mo.FindInventory('BasicArmor');
		if (item != NULL && item.Amount > 0)
		{
			DrawTexture(item.Icon, (2, 9), true, 1.0, itemAlign:ALIGN_OFFSETS);
			DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (34, 23), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
		}

		// Ammo
		Inventory ammo1, ammo2;
		int ammocount1, ammocount2;

		[ammo1, ammo2, ammocount1, ammocount2] = GetCurrentAmmo ();
		if (ammo1 != NULL)
		{
			DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 5, 0), (318, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
			DrawTexture (ammo1.Icon, (290, 13), true, 1.0, itemAlign:ALIGN_OFFSETS);
		}

		// Sigil
		item = CPlayer.mo.FindInventory('Sigil');
		if (item != NULL)
		{
			DrawTexture (item.Icon, (253, 7), true, 1.0, itemAlign:ALIGN_OFFSETS);
		}

		// Inventory
		CPlayer.inventorytics = 0;
		CPlayer.mo.InvFirst = ValidateInvFirst (6);
		i = 0;
		for (item = CPlayer.mo.InvFirst; item != NULL && i < 6; item = item.NextInv())
		{
			if (item == CPlayer.mo.InvSel)
			{
				DrawTexture (item.Icon, (42 + 35*i, 12), true, 1. - ItemFlash, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0);
			}
			if (item.Icon.isValid())
			{
				DrawTexture (item.Icon, (48 + 35*i, 14), true, 1.0, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0);
			}
			DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (81 + 35*i, 23), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
			i++;
		}
	}

	protected void DrawFullScreenStuff ()
	{
		// Draw health
		
		DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 0, 0), (4, -10), 1., (CPlayer.health < CPlayer.mo.RunHealth)? Font.CR_BRICK : Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_LEFT|ALIGN_BOTTOM, 7, true, 1, 1);
		DrawTexture(Images[imgMEDI], (14, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_LEFT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);

		// Draw armor
		let armor = CPlayer.mo.FindInventory('BasicArmor');
		if (armor != NULL && armor.Amount != 0)
		{
			DrawString("Indexfont_Strife_Yellow", FormatNumber(armor.Amount, 3, 0, 0), (35, -10), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_LEFT|ALIGN_BOTTOM, 7, true, 1, 1);
			DrawTexture(armor.Icon, (45, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_LEFT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
		}

		// Draw ammo
		Inventory ammo1, ammo2;
		int ammocount1, ammocount2;

		[ammo1, ammo2, ammocount1, ammocount2] = GetCurrentAmmo ();
		if (ammo1 != NULL)
		{
			// Draw primary ammo in the bottom-right corner
			DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 0, 0), (-23, -10), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_BOTTOM, 7, true, 1, 1);
			DrawTexture(ammo1.Icon, (-14, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
			if (ammo2 != NULL && ammo1!=ammo2)
			{
				// Draw secondary ammo just above the primary ammo
				DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 0, 0), (-23, -48), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_BOTTOM, 7, true, 1, 1);
				DrawTexture(ammo1.Icon, (-14, -55), false, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
			}
		}

		if (deathmatch)
		{ // Draw frags (in DM)
			DrawString("BigFont", FormatNumber(CPlayer.FragCount, 3, 0, 0), (-44, 1), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_TOP, 0, false, 2, 2);
		}

		// Draw inventory
		if (CPlayer.inventorytics == 0)
		{
			if (CPlayer.mo.InvSel != null)
			{
				if (ItemFlash > 0)
				{
					DrawTexture(Images[CursorImage], (-28, -15), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_RIGHT);
				}
				DrawString("Indexfont_Strife_Yellow", FormatNumber(CPlayer.mo.InvSel.Amount, 3, 5, 0), (-23, -10), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, ALIGN_BOTTOM|ALIGN_RIGHT, 7, true, 1, 1);
				DrawTexture(CPlayer.mo.InvSel.Icon, (-42, -17), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_HCENTER, CPlayer.mo.InvSel.Amount > 0 ? 0 : DI_DIM);
			}
		}
		else
		{
			CPlayer.mo.InvFirst = ValidateInvFirst (6);
			int i = 0;
			Inventory item;
			Vector2 box = TexMan.GetScaledSize(Images[CursorImage]) - (4, 4);	// Fit oversized icons into the box.
			if (CPlayer.mo.InvFirst != NULL)
			{
				for (item = CPlayer.mo.InvFirst; item != NULL && i < 6; item = item.NextInv())
				{
					if (item == CPlayer.mo.InvSel)
					{
						DrawTexture(Images[CursorImage], (-90+i*35, -3), true, 0.75, ALIGN_CENTER_BOTTOM, ItemAlign:ALIGN_CENTER_BOTTOM);
					}
					if (item.Icon.isValid())
					{
						DrawTexture(item.Icon, (-90+i*35, -5), true, 0.75, ALIGN_CENTER_BOTTOM, box, ALIGN_CENTER_BOTTOM, CPlayer.mo.InvSel.Amount > 0 ? 0 : DI_DIM);
					}
					DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (-65 + i*35, -8), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, ALIGN_CENTER_BOTTOM, 7, true, 1, 1);
					++i;
				}
			}
		}
		fullscreenoffsets = false;
	}

	protected void DrawPopScreen (int bottom, double TicFrac)
	{
		String buff;
		String label;
		int i;
		Inventory item;
		int xscale, yscale, left, top;
		int bars = (CurrentPop == POP_Status) ? imgINVPOP : imgINVPOP2;
		int back = (CurrentPop == POP_Status) ? imgINVPBAK : imgINVPBAK2;
		// Extrapolate the height of the popscreen for smoother movement
		int height = clamp (PopHeight + int(TicFrac * PopHeightChange), -POP_HEIGHT, 0);

		xscale = CleanXfac;
		yscale = CleanYfac;
		left = screen.GetWidth()/2 - 160*CleanXfac;
		top = bottom + height * yscale;

		screen.DrawTexture (Images[back], true, left, top, DTA_CleanNoMove, true, DTA_Alpha, 0.75);
		screen.DrawTexture (Images[bars], true, left, top, DTA_CleanNoMove, true);


		switch (CurrentPop)
		{
		case POP_Log:
		{
			// Draw the latest log message.
			screen.DrawText(SmallFont2, Font.CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, Level.TimeFormatted(),
				DTA_CleanNoMove, true);

			if (CPlayer.LogText.Length() > 0)
			{
				BrokenLines lines = SmallFont2.BreakLines(CPlayer.LogText, 272);
				for (i = 0; i < lines.Count(); ++i)
				{
					screen.DrawText(SmallFont2, Font.CR_UNTRANSLATED, left + 24 * xscale, top + (18 + i * 12)*yscale,
						lines.StringAt(i), DTA_CleanNoMove, true);
				}
			}
			break;
		}

		case POP_Keys:
			// List the keys the player has.
			int pos, endpos, leftcol;
			int clipleft, clipright;
			
			pos = KeyPopPos;
			endpos = pos + 10;
			leftcol = 20;
			clipleft = left + 17*xscale;
			clipright = left + (320-17)*xscale;
			if (KeyPopScroll > 0)
			{
				// Extrapolate the scroll position for smoother scrolling
				int scroll = MAX (0, KeyPopScroll - int(TicFrac * (280./KEY_TIME)));
				pos -= 10;
				leftcol = leftcol - 280 + scroll;
			}
			i = 0;
			for (item = CPlayer.mo.Inv; i < endpos && item != NULL; item = item.Inv)
			{
				if (!(item is "Key"))
					continue;
				
				if (i < pos)
				{
					i++;
					continue;
				}

				label = item.GetTag();

				int colnum = ((i-pos) / 5) & (KeyPopScroll > 0 ? 3 : 1);
				int rownum = (i % 5) * 18;

				screen.DrawTexture (item.Icon, true,
					left + (colnum * 140 + leftcol)*xscale,
					top + (6 + rownum)*yscale,
					DTA_CleanNoMove, true,
					DTA_ClipLeft, clipleft,
					DTA_ClipRight, clipright);
				screen.DrawText (SmallFont2, Font.CR_UNTRANSLATED,
					left + (colnum * 140 + leftcol + 17)*xscale,
					top + (11 + rownum)*yscale,
					label,
					DTA_CleanNoMove, true,
					DTA_ClipLeft, clipleft,
					DTA_ClipRight, clipright);
				i++;
			}
			break;

		case POP_Status:
			// Show miscellaneous status items.
			
			// Print stats
			DrINumber2 (CPlayer.mo.accuracy, left+268*xscale, top+28*yscale, 7*xscale, imgFONY0);
			DrINumber2 (CPlayer.mo.stamina, left+268*xscale, top+52*yscale, 7*xscale, imgFONY0);

			// How many keys does the player have?
			i = 0;
			for (item = CPlayer.mo.Inv; item != NULL; item = item.Inv)
			{
				if (item is "Key")
				{
					i++;
				}
			}
			DrINumber2 (i, left+268*xscale, top+76*yscale, 7*xscale, imgFONY0);

			// Does the player have a communicator?
			item = CPlayer.mo.FindInventory ("Communicator");
			if (item != NULL)
			{
				screen.DrawTexture (item.Icon, true,
					left + 280*xscale,
					top + 74*yscale,
					DTA_CleanNoMove, true);
			}

			// How much ammo does the player have?
			static const class<Ammo> AmmoList[] = {
				"ClipOfBullets",			
				"PoisonBolts",				
				"ElectricBolts",			
				"HEGrenadeRounds",			
				"PhosphorusGrenadeRounds",	
				"MiniMissiles",			
				"EnergyPod"};				
				
			static const int AmmoY[] = {19, 35, 43, 59, 67, 75, 83};
			
			for (i = 0; i < 7; ++i)
			{
				item = CPlayer.mo.FindInventory (AmmoList[i]);

				if (item == NULL)
				{
					DrINumber2 (0, left+206*xscale, top+AmmoY[i] * yscale, 7*xscale, imgFONY0);
					DrINumber2 (GetDefaultByType(AmmoList[i]).MaxAmount, left+239*xscale, top+AmmoY[i] * yscale, 7*xscale, imgFONY0);
				}
				else
				{
					DrINumber2 (item.Amount, left+206*xscale, top+AmmoY[i] * yscale, 7*xscale, imgFONY0);
					DrINumber2 (item.MaxAmount, left+239*xscale, top+AmmoY[i] * yscale, 7*xscale, imgFONY0);
				}
			}
					

			// What weapons does the player have?
			static const class<Weapon> WeaponList[] = 
			{
				"StrifeCrossbow",
				"AssaultGun",
				"FlameThrower",
				"MiniMissileLauncher",
				"StrifeGrenadeLauncher",
				"Mauler"
			};
			static const int WeaponX[] = {23, 21, 57, 20, 55, 52};
			static const int WeaponY[] = {19, 41, 50, 64, 20, 75};

			for (i = 0; i < 6; ++i)
			{
				item = CPlayer.mo.FindInventory (WeaponList[i]);
				if (item != NULL)
				{
					screen.DrawTexture (item.Icon, true,
						left + WeaponX[i] * xscale,
						top + WeaponY[i] * yscale,
						DTA_CleanNoMove, true,
						DTA_LeftOffset, 0,
						DTA_TopOffset, 0);
				}
			}
			break;
		}
	}

	void DrINumber2 (int val, int x, int y, int width, int imgBase) const
	{
		x -= width;

		if (val == 0)
		{
			screen.DrawTexture (Images[imgBase], true, x, y, DTA_CleanNoMove, true);
		}
		else
		{
			while (val != 0)
			{
				screen.DrawTexture (Images[imgBase+val%10], true, x, y, DTA_CleanNoMove, true);
				val /= 10;
				x -= width;
			}
		}
	}
}

