
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,
		imgINVPOP,
		imgINVPOP2,
		imgINVPBAK,
		imgINVPBAK2,
		imgFONY0,
		imgFONY1,
		imgFONY2,
		imgFONY3,
		imgFONY4,
		imgFONY5,
		imgFONY6,
		imgFONY7,
		imgFONY8,
		imgFONY9,
		imgFONY_PERCENT,
		imgNEGATIVE,
	};
	
	TextureID Images[imgNEGATIVE + 1];
	int CursorImage;
	int CurrentPop, PendingPop, PopHeight, PopHeightChange;
	int KeyPopPos, KeyPopScroll;
	
	HUDFont mYelFont, mGrnFont, mBigFont;

	override void Init()
	{
		static const Name strifeLumpNames[] =
		{
			"INVCURS", "CURSOR01", "INVPOP", "INVPOP2",
			"INVPBAK", "INVPBAK2",
			"INVFONY0", "INVFONY1", "INVFONY2", "INVFONY3", "INVFONY4",
			"INVFONY5", "INVFONY6", "INVFONY7", "INVFONY8", "INVFONY9",
			"INVFONY%", ""

		};
		
		Super.Init();
		SetSize(32, 320, 200);
		Reset();
		
		for(int i = 0; i <= imgNEGATIVE; i++)
		{
			Images[i] = TexMan.CheckForTexture(strifeLumpNames[i], TexMan.TYPE_MiscPatch);
		}

		CursorImage = Images[imgINVCURS].IsValid() ? imgINVCURS : imgCURSOR01;
		
		mYelFont = HUDFont.Create("Indexfont_Strife_Yellow", 7, Mono_CellLeft, 1, 1);
		mGrnFont = HUDFont.Create("Indexfont_Strife_Green", 7, Mono_CellLeft, 1, 1);
		mBigFont = HUDFont.Create("BigFont", 0, Mono_Off, 2, 2);
	}

	override void NewGame ()
	{
		Super.NewGame();
		Reset ();
	}

	override int GetProtrusion(double scaleratio) const
	{
		return 10;
	}

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

		if (state == HUD_StatusBar)
		{
			BeginStatusBar();
			DrawMainBar (TicFrac);
		}
		else
		{
			if (state == HUD_Fullscreen)
			{
				BeginHUD();
				DrawFullScreenStuff ();
			}

			// Draw pop screen (log, keys, and status)
			if (CurrentPop != POP_None && PopHeight < 0)
			{
				// This uses direct low level draw commands and would otherwise require calling
				// BeginStatusBar(true);
				DrawPopScreen (screen.GetHeight(), TicFrac);
			}
		}
	}

	override void ShowPop (int popnum)
	{
		Super.ShowPop(popnum);
		if (popnum == CurrentPop || (popnum == POP_LOG && MustDrawLog(0)))
		{
			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 generic_ui || log_vgafont;
	}

	void Reset ()
	{
		CurrentPop = POP_None;
		PendingPop = POP_NoChange;
		PopHeight = 0;
		KeyPopPos = 0;
		KeyPopScroll = 0;
	}

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

		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;
				}
			}
		}
	}

	private void FillBar(double x, double y, double start, double stopp, Color color1, Color color2)
	{
		Fill(color1, x, y, (stopp-start)*2, 1);
		Fill(color2, x, y+1, (stopp-start)*2, 1);
	}
	
	protected void DrawHealthBar(int health, int x, int y)
	{
		Color green1 = Color(255, 180, 228, 128);	// light green
		Color green2 = Color(255, 128, 180, 80);	// dark green

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

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

		Color red1 = Color(255, 216, 44,  44);	// light red
		Color red2 = Color(255, 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 + stopp * 2, 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)
		{
			double tmp, h;
			[tmp, tmp, h] = StatusbarToRealCoords(0, 0, 8);
			DrawPopScreen (int(GetTopOfStatusBar() - h), TicFrac);
		}

		DrawImage("INVBACK", (0, 168), DI_ITEM_OFFSETS);
		DrawImage("INVTOP", (0, 160), DI_ITEM_OFFSETS);

		// Health
		DrawString(mGrnFont, FormatNumber(CPlayer.health, 3, 5), (79, 162), DI_TEXT_ALIGN_RIGHT);
		int points;
		if (CPlayer.cheats & CF_GODMODE)
		{
			points = 999;
		}
		else
		{
			points = min(CPlayer.health, 200);
		}
		DrawHealthBar (points, 49, 172);
		DrawHealthBar (points, 49, 175);

		// Armor
		item = CPlayer.mo.FindInventory('BasicArmor', true);
		if (item != NULL && item.Amount > 0)
		{
			DrawInventoryIcon(item, (2, 177), DI_ITEM_OFFSETS);
			DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (27, 191), DI_TEXT_ALIGN_RIGHT);
		}

		// Ammo
		Inventory ammo1 = GetCurrentAmmo ();
		if (ammo1 != NULL)
		{
			DrawString(mGrnFont, FormatNumber(ammo1.Amount, 3, 5), (311, 162), DI_TEXT_ALIGN_RIGHT);
			DrawInventoryIcon (ammo1, (290, 181), DI_ITEM_OFFSETS);
		}

		// Sigil
		item = CPlayer.mo.FindInventory('Sigil');
		if (item != NULL)
		{
			DrawInventoryIcon (item, (253, 175), DI_ITEM_OFFSETS);
		}

		// Inventory
		CPlayer.inventorytics = 0;
		CPlayer.mo.InvFirst = ValidateInvFirst (6);
		i = 0;
		for (item = CPlayer.mo.InvFirst; item != NULL && i < 6; item = item.NextInv())
		{
			int flags = item.Amount <= 0? DI_ITEM_OFFSETS|DI_DIM : DI_ITEM_OFFSETS;
			if (item == CPlayer.mo.InvSel)
			{
				DrawTexture (Images[CursorImage], (42 + TICRATE*i, 180), flags, 1. - itemflashFade);
			}
			DrawInventoryIcon (item, (48 + TICRATE*i, 182), flags);
			DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (75 + TICRATE*i, 191), DI_TEXT_ALIGN_RIGHT);
			i++;
		}
	}

	protected void DrawFullScreenStuff ()
	{
		// Draw health (use red color if health is below the run health threashold.)
		DrawString(mGrnFont, FormatNumber(CPlayer.health, 3), (4, -10), DI_TEXT_ALIGN_LEFT, (CPlayer.health < CPlayer.mo.RunHealth)? Font.CR_BRICK : Font.CR_UNTRANSLATED);
		DrawImage("I_MDKT", (14, -17));

		// Draw armor
		let armor = CPlayer.mo.FindInventory('BasicArmor', true);
		if (armor != NULL && armor.Amount != 0)
		{
			DrawString(mYelFont, FormatNumber(armor.Amount, 3), (35, -10));
			DrawInventoryIcon(armor, (45, -17));
		}

		// 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(mGrnFont, FormatNumber(ammo1.Amount, 3), (-23, -10));
			DrawInventoryIcon(ammo1, (-14, -17));
			if (ammo2 != NULL && ammo1!=ammo2)
			{
				// Draw secondary ammo just above the primary ammo
				DrawString(mGrnFont, FormatNumber(ammo2.Amount, 3), (-23, -48));
				DrawInventoryIcon(ammo2, (-14, -55));
			}
		}

		if (deathmatch)
		{ // Draw frags (in DM)
			DrawString(mBigFont, FormatNumber(CPlayer.FragCount, 3), (4, 1));
		}

		// Draw inventory
		if (CPlayer.inventorytics == 0)
		{
			if (CPlayer.mo.InvSel != null)
			{
				if (itemflashFade > 0)
				{
					DrawTexture(Images[CursorImage], (-42, -15));
				}
				DrawString(mYelFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3, 5), (-30, -10), DI_TEXT_ALIGN_RIGHT);
				DrawInventoryIcon(CPlayer.mo.InvSel, (-42, -17), DI_DIMDEPLETED);
			}
		}
		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*TICRATE, -3), DI_SCREEN_CENTER_BOTTOM, 0.75);
					}
					if (item.Icon.isValid())
					{
						DrawInventoryIcon(item, (-90+i*TICRATE, -5), DI_SCREEN_CENTER_BOTTOM|DI_DIMDEPLETED, 0.75);
					}
					DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (-72 + i*TICRATE, -8), DI_TEXT_ALIGN_RIGHT|DI_SCREEN_CENTER_BOTTOM);
					++i;
				}
			}
		}
	}

	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)
			{
				let text = Stringtable.Localize(CPlayer.LogText);
				BrokenLines lines = SmallFont2.BreakLines(text, 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;
			}
		}
	}
}

