#region Copyright
/*
--------------------------------------------------------------------------------
This source file is part of Xenocide
by Project Xenocide Team
For the latest info on Xenocide, see http://www.projectxenocide.com/
This work is licensed under the Creative Commons
Attribution-NonCommercial-ShareAlike 2.5 License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-nc-sa/2.5/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor,
San Francisco, California, 94105, USA.
--------------------------------------------------------------------------------
*/
/*
* @file ResearchScreen.cs
* @date Created: 2007/09/30
* @author File creator: David Teviotdale
* @author Credits: none
*/
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using CeGui;
using ProjectXenocide.Utils;
using ProjectXenocide.Model.Geoscape;
using ProjectXenocide.Model.Geoscape.Outposts;
using ProjectXenocide.Model.StaticData.Items;
using ProjectXenocide.Model.StaticData.Research;
using ProjectXenocide.Model;
using Xenocide.Resources;
#endregion
namespace ProjectXenocide.UI.Screens
{
///
/// This is the screen that shows Topics being researched and available for research
///
public class ResearchScreen : Screen
{
///
/// Constructor (obviously)
///
public ResearchScreen()
: base("Research")
{
}
#region Create the CeGui widgets
///
/// add the buttons to the screen
///
protected override void CreateCeguiWidgets()
{
// Get projects to bring their progress up to date
ProjectMgr.Update();
FindIdleScientists();
// Text giving number of idle scientists
availableText = AddStaticText(0.01f, 0.01f, 0.7f, 0.08f);
availableText.Text = MakeIdleScientistsString();
availableText.HorizontalFormat = HorizontalTextFormat.WordWrapLeft;
// The gird of research projects
InitializeGrid();
PopulateGrid();
// buttons
addIdleScientistsButton = AddButton("BUTTON_ADD_IDLE_SCIENTISTS", 0.7475f, 0.75f, 0.2275f, 0.04125f, "PlanetView\\zoomin.ogg");
moreScientistsButton = AddButton("BUTTON_MORE_SCIENTISTS", 0.7475f, 0.80f, 0.2275f, 0.04125f, "PlanetView\\zoomin.ogg");
lessScientistsButton = AddButton("BUTTON_LESS_SCIENTISTS", 0.7475f, 0.85f, 0.2275f, 0.04125f, "PlanetView\\zoomout.ogg");
removeAllScientistsButton = AddButton("BUTTON_REMOVE_ALL_SCIENTISTS", 0.7475f, 0.90f, 0.2275f, 0.04125f, "PlanetView\\zoomout.ogg");
closeButton = AddButton("BUTTON_CLOSE", 0.7475f, 0.95f, 0.2275f, 0.04125f);
moreScientistsButton.Clicked += new CeGui.GuiEventHandler(OnMoreButton);
lessScientistsButton.Clicked += new CeGui.GuiEventHandler(OnLessButton);
addIdleScientistsButton.Clicked += new CeGui.GuiEventHandler(OnAddIdleButton);
removeAllScientistsButton.Clicked += new CeGui.GuiEventHandler(OnRemoveAllButton);
closeButton.Clicked += new CeGui.GuiEventHandler(OnCloseButton);
}
private CeGui.Widgets.StaticText availableText;
private CeGui.Widgets.MultiColumnList grid;
private CeGui.Widgets.PushButton moreScientistsButton;
private CeGui.Widgets.PushButton lessScientistsButton;
private CeGui.Widgets.PushButton removeAllScientistsButton;
private CeGui.Widgets.PushButton addIdleScientistsButton;
private CeGui.Widgets.PushButton closeButton;
///
/// Create MultiColumnListBox which holds items being shiped
///
private void InitializeGrid()
{
grid = GuiBuilder.CreateGrid("researchGrid");
AddWidget(grid, 0.01f, 0.13f, 0.70f, 0.86f);
grid.AddColumn(Strings.SCREEN_RESEARCH_COLUMN_PROJECT, grid.ColumnCount, 0.50f);
grid.AddColumn(Strings.SCREEN_RESEARCH_COLUMN_SCIENTISTS, grid.ColumnCount, 0.25f);
grid.AddColumn(Strings.SCREEN_RESEARCH_COLUMN_ETA, grid.ColumnCount, 0.22f);
}
///
/// Put the list of items being shiped into the grid
///
private void PopulateGrid()
{
// active projects at top
foreach (ResearchProject project in ProjectMgr)
{
AddRowToGrid(new ProjectLineItem(project));
}
// followed by projects that could be started
ResearchGraph graph = Xenocide.StaticTables.ResearchGraph;
foreach (ResearchTopic topic in graph.StartableTopics(TechMgr, Outposts))
{
if (!ProjectMgr.IsInProgress(topic.Id))
{
AddRowToGrid(new TopicLineItem(topic));
}
}
}
///
/// Add a row to the grid
///
/// data to put on line
private void AddRowToGrid(LineItem lineItem)
{
CeGui.ListboxTextItem listboxItem = Util.CreateListboxItem(lineItem.Name);
int rowNum = grid.AddRow(listboxItem, 0);
listboxItem.ID = rowNum;
Util.AddStringElementToGrid(grid, 1, rowNum, lineItem.DisplayNumWorkers);
Util.AddStringElementToGrid(grid, 2, rowNum, lineItem.Eta);
// and record details of this item
lineItems[rowNum] = lineItem;
}
#endregion Create the CeGui widgets
#region event handlers
/// React to user pressing the More Scientists
/// Not used
/// Not used
private void OnMoreButton(object sender, CeGui.GuiEventArgs e)
{
AddIdleScientists(1);
}
/// React to user pressing the Add Idle Scientists Button
/// Not used
/// Not used
private void OnAddIdleButton(object sender, CeGui.GuiEventArgs e)
{
AddIdleScientists(idleScientists.Count);
}
/// React to user pressing the Remove All Scientists Button
/// Not used
/// Not used
private void OnRemoveAllButton(object sender, CeGui.GuiEventArgs e)
{
RemoveAllScientists();
}
/// React to user pressing the Less Scientists button
/// Not used
/// Not used
private void OnLessButton(object sender, CeGui.GuiEventArgs e)
{
RemoveScientist();
}
/// React to user pressing the Close button
/// Not used
/// Not used
private void OnCloseButton(object sender, CeGui.GuiEventArgs e)
{
GoToGeoscapeScreen();
}
#endregion event handlers
///
/// Add scientists to the currently selected project
///
/// number of scientists to add
private void AddIdleScientists(int count)
{
CeGui.Widgets.ListboxItem selectedItem = GetSelectedItem();
if (null != selectedItem)
{
// can only add scientist if we have one that's idle
if (0 < idleScientists.Count)
{
Debug.Assert((0 < count) && (count <= idleScientists.Count));
ProjectLineItem project = lineItems[selectedItem.ID].GetProject();
// update lineItems in case we've promoted from TopicLine to ProjectLine
lineItems[selectedItem.ID] = project;
// add specified number of idle scientists to the project
for (int i = 0; i < count; ++i)
{
project.AddWorker(idleScientists);
}
UpdateDetails(selectedItem, project);
// we may have started a new project and consumed an artifact needed to
// start other research topics
RemoveUnavailableTopics();
}
else
{
Util.ShowMessageBox(Strings.MSGBOX_NO_IDLE_SCIENTISTS);
}
}
}
///
/// Remove a scientist from the currently selected project
///
private void RemoveScientist()
{
CeGui.Widgets.ListboxItem selectedItem = GetSelectedItem();
if (null != selectedItem)
{
LineItem lineItem = lineItems[selectedItem.ID];
lineItem.RemoveWorker(idleScientists);
UpdateDetails(selectedItem, lineItem);
}
}
///
/// Remove all scientists from the currently selected project
///
private void RemoveAllScientists()
{
CeGui.Widgets.ListboxItem selectedItem = GetSelectedItem();
if (null != selectedItem)
{
LineItem lineItem = lineItems[selectedItem.ID];
while (0 < lineItem.NumWorkers)
{
lineItem.RemoveWorker(idleScientists);
}
UpdateDetails(selectedItem, lineItem);
}
}
///
/// Update the screen to reflect the latest changes
///
/// row in gird that is selected
/// LineItem associated with this row
private void UpdateDetails(CeGui.Widgets.ListboxItem selectedItem, LineItem lineItem)
{
availableText.Text = MakeIdleScientistsString();
// update row in grid
int row = grid.GetRowIndexOfItem(selectedItem);
CeGui.Widgets.GridReference position = new CeGui.Widgets.GridReference(row, 1);
grid.GetItemAtGridReference(position).Text = lineItem.DisplayNumWorkers;
position.Column = 2;
grid.GetItemAtGridReference(position).Text = lineItem.Eta;
}
///
/// Remove any rows from the grid that can no longer be researched
///
private void RemoveUnavailableTopics()
{
CeGui.Widgets.GridReference position = new CeGui.Widgets.GridReference(0, 0);
for (int i = 0; i < grid.RowCount; ++i)
{
position.Row = i;
if (!lineItems[grid.GetItemAtGridReference(position).ID].CanResearch)
{
grid.RemoveRow(i);
}
}
}
///
/// Close this screen and go back to the Geoscape screen
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope",
Justification = "FxCop False Positive")]
private void GoToGeoscapeScreen()
{
ScreenManager.ScheduleScreen(new GeoscapeScreen());
}
// Get currently selected item from Grid. Give error message if nothing selected
private CeGui.Widgets.ListboxItem GetSelectedItem()
{
CeGui.Widgets.ListboxItem selectedItem = grid.GetFirstSelectedItem();
if (null == selectedItem)
{
Util.ShowMessageBox(Strings.MSGBOX_NO_PROJECT_SELECTED);
}
return selectedItem;
}
///
/// Make up text to show, giving number of Idle scientists
///
/// text to show
private String MakeIdleScientistsString()
{
return Util.StringFormat(Strings.SCREEN_RESEARCH_IDLE_SCIENTISTS, idleScientists.Count);
}
///
/// Find all the scientists (in X-Corp as whole) that are not doing anything
/// but have available lab space to work in
///
private void FindIdleScientists()
{
foreach (Outpost outpost in Outposts)
{
uint spaceFree = outpost.Statistics.Capacities["STORAGE_SCIENTIST"].Available;
int count = -1;
foreach (Person p in outpost.Inventory.ListStaff("ITEM_PERSON_SCIENTIST", false))
{
if (++count < spaceFree)
{
idleScientists.Add(p);
}
}
}
}
///
/// Holds the data for a line in the grid
///
private abstract class LineItem
{
///
/// Constructor
///
protected LineItem() { }
///
/// Remove a worker from the line item
///
/// list of idle workers to add now idle woker to
public virtual void RemoveWorker(IList idle) { }
///
/// Get the project line represented by this line in the Grid, creating a project if necessary
///
/// line to put in grid for this topic
public abstract ProjectLineItem GetProject();
#region Fields
///
/// Value to show in "Name" column
///
public abstract string Name { get; }
///
/// Value to show in "Assigned Scientists" column
///
public virtual string DisplayNumWorkers { get { return String.Empty; } }
///
/// Number of workers assigned to project
///
public virtual int NumWorkers { get { return 0; } }
///
/// Value to show in "Days Left" column
///
public virtual string Eta { get { return String.Empty; } }
///
/// Can line item still be researched?
///
public virtual bool CanResearch { get { return true; } }
#endregion Fields
}
private class ProjectLineItem : LineItem
{
///
/// Constructor
///
/// Research Project this line is giving details for
public ProjectLineItem(ResearchProject project)
{
this.project = project;
}
///
/// Add a worker to the line item
///
/// list of idle workers to get worker from
public void AddWorker(IList idle)
{
Person worker = idle[idle.Count - 1];
idle.RemoveAt(idle.Count - 1);
project.Add(worker);
}
///
/// Remove a worker from the line item
///
/// list of idle workers to add now idle woker to
public override void RemoveWorker(IList idle)
{
if (0 < project.NumWorkers)
{
idle.Add(project.RemoveWorker());
}
}
///
/// Get the project line represented by this line in the Grid, creating a project if necessary
///
/// line to put in grid for this topic
public override ProjectLineItem GetProject()
{
return this;
}
#region Fields
///
/// Value to show in "Name" column
///
public override string Name { get { return project.Name; } }
///
/// Value to show in "Assigned Scientists" column
///
public override string DisplayNumWorkers { get { return Util.ToString(NumWorkers); } }
///
/// Number of workers assigned to project
///
public override int NumWorkers { get { return project.NumWorkers; } }
///
/// Value to show in "Days Left" column
///
public override string Eta { get { return project.CalcEtaToShow(); } }
///
/// Research Project this line gives details for
///
private ResearchProject project;
#endregion Fields
}
private class TopicLineItem : LineItem
{
///
/// Constructor
///
/// ResearchTopic this line is giving details for
public TopicLineItem(ResearchTopic topic)
{
this.topic = topic;
}
///
/// Get the project line represented by this line in the Grid, creating a project if necessary
///
/// line to put in grid for this topic
public override ProjectLineItem GetProject()
{
return new ProjectLineItem(ProjectMgr.CreateProject(topic.Id, TechMgr, Outposts));
}
#region Fields
///
/// Value to show in "Name" column
///
public override string Name { get { return topic.Name; } }
///
/// Can line item still be researched?
///
public override bool CanResearch { get { return topic.CanResearch(TechMgr, Outposts); } }
///
/// Research Topic this line gives details for
///
private ResearchTopic topic;
#endregion Fields
}
#region Fields
///
/// Shortcut
///
private static ResearchProjectManager ProjectMgr
{
get { return Xenocide.GameState.GeoData.XCorp.ResearchManager; }
}
///
/// Shortcut
///
private static TechnologyManager TechMgr
{
get { return Xenocide.GameState.GeoData.XCorp.TechManager; }
}
///
/// Shortcut
///
private static ICollection Outposts
{
get { return Xenocide.GameState.GeoData.Outposts; }
}
///
/// Bind lines in grid to object providing data to show.
/// format is Dictionary<line id, LineData>
///
private Dictionary lineItems = new Dictionary();
///
/// Scienists that currently are not working, but could work
///
private List idleScientists = new List();
#endregion Fields
}
}