package ch.sahits.game.graphic.display.dialog;
import java.awt.Color;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;
import java.io.IOException;
import ch.sahits.game.event.EViewChangeEvent;
import ch.sahits.game.event.Event;
import ch.sahits.game.event.IEventListener;
import ch.sahits.game.event.KeyPressEvent;
import ch.sahits.game.event.MouseClickEvent;
import ch.sahits.game.event.ViewChangeEvent;
import ch.sahits.game.graphic.display.gameplay.MainView;
import ch.sahits.game.graphic.display.model.CityPlayerProxy;
import ch.sahits.game.graphic.display.notice.NoticeView;
import ch.sahits.game.graphic.display.util.ClickablePolygons;
import ch.sahits.game.graphic.image.DisplayImageDIResolver;
import ch.sahits.game.graphic.image.IImageLoader;
import ch.sahits.game.graphic.image.IOpenPatricianPainter;
import ch.sahits.game.graphic.image.model.NamedPolygon;
import ch.sahits.game.image.IImageUtilities;
import ch.sahits.game.openpatrician.model.city.BuildingProduction;
import ch.sahits.game.openpatrician.model.city.CityProduction;
import ch.sahits.game.openpatrician.model.city.EPopulationClass;
import ch.sahits.game.openpatrician.model.city.ICity;
import ch.sahits.game.openpatrician.model.city.PopulationConsume;
import ch.sahits.game.openpatrician.model.product.AmountablePrice;
import ch.sahits.game.openpatrician.model.product.EWare;
import ch.sahits.game.openpatrician.model.product.IWare;
import ch.sahits.game.rendering.RenderablePart;
/**
* This is a statistical dialog displaying the socked wares in the city and their prices.
* @author Andi Hotz, (c) Sahits GmbH, 2012
* Created on Jul 17, 2012
*
*/
public class ConsumtionProductionStockDialog extends OpenPatricianGameDialog implements IEventListener, RenderablePart{
private boolean enabled = true;
private ClickablePolygons footerPolygons;
/** Hold all the positioning information, initialized in initBackgroundImage */
private DialogPositions positions;
/** reference to the utilities for image manipulation */
private IImageUtilities imageUtils;
private IOpenPatricianPainter opPainter;
public ConsumtionProductionStockDialog(Point topLeft, double scale,
CityPlayerProxy cityProxy) {
super(topLeft, DisplayImageDIResolver.getInstance().getMainScreenLoader(), scale, cityProxy);
Event.add(this);
}
@Override
protected void init() {
DisplayImageDIResolver resolver = DisplayImageDIResolver.getInstance();
opPainter = resolver.getOpenPatricianPainter();
imageUtils = resolver.getImageUtilities();
super.init();
}
/**
* Compute the insets as a factor of the scaling
* @param scale
*/
protected void initInsets(double scale) {
int top = (int) Math.ceil(scale*30);
int side = (int) Math.ceil(scale*3);
inset = new Insets(top, side, top, side);
}
@Override
protected void initiatePolygons() {
footerPolygons = new ClickablePolygons();
}
@Override
public void gameUpdate(Event e, Object notice) {
if (e instanceof KeyPressEvent){
KeyEvent key= ((KeyPressEvent)e).getKey();
if (key.getKeyCode()==KeyEvent.VK_ESCAPE){
new ViewChangeEvent(MainView.class).notify(EViewChangeEvent.CLOSE_DIALOG);
new ViewChangeEvent(NoticeView.class).notify(EViewChangeEvent.NOTICE_HIDE);
Event.remove(this);
}
}
if (e instanceof MouseClickEvent){
footerPolygons.testAndExecute((Point) notice);
}
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public void setEnabled(boolean flag) {
enabled=flag;
}
/**
* Draw the table header
* @param g2d
* @param y position of the table header baseline
* @throws FontFormatException
* @throws IOException
*/
private void drawTableHeader(Graphics2D g2d,final int y) throws FontFormatException, IOException{
GlyphVector gv = opPainter.createGlyphVector(g2d, "Ware", 19); // TODO externalize
int x = positions.xWare-(int)Math.rint(gv.getVisualBounds().getWidth());
g2d.drawGlyphVector(gv, x, y);
String columnTitle = "Stock";
gv = opPainter.createGlyphVector(g2d, columnTitle, 19);
g2d.drawGlyphVector(gv, positions.xCity, y);
gv = opPainter.createGlyphVector(g2d, "City", 19);
g2d.drawGlyphVector(gv, positions.prodCity, y);
gv = opPainter.createGlyphVector(g2d, "Shops", 19);
g2d.drawGlyphVector(gv, positions.prodChandler, y);
gv = opPainter.createGlyphVector(g2d, "Pop.", 19);
g2d.drawGlyphVector(gv, positions.consCiticens, y);
gv = opPainter.createGlyphVector(g2d, "Shops", 19);
g2d.drawGlyphVector(gv, positions.consWorkshops, y);
gv = opPainter.createGlyphVector(g2d, "Tot.", 19);
g2d.drawGlyphVector(gv, positions.consTotal, y);
}
@Override
protected BufferedImage initBackgroundImage(IImageLoader loader,Point topLeft) {
BufferedImage bg = super.initBackgroundImage(loader,topLeft); // get a copy
Graphics2D g2d = bg.createGraphics();
g2d.setColor(Color.BLACK);
try {
GlyphVector gv = opPainter.createGlyphVector(g2d, "Production and Consumtion", 24); // TODO externalize
double titleHeight = gv.getVisualBounds().getHeight();
int length = (int) Math.rint(gv.getVisualBounds().getWidth());
int x = ((bg.getWidth()-getInset().left-getInset().right)-length)/2;
int y = getInset().top+10+(int)Math.rint(titleHeight*2/3);
g2d.drawGlyphVector(gv, x, y);
// Dynamic row
y += titleHeight;
y += (int)Math.rint(titleHeight*2/3);
BufferedImage waxSeal = loader.getImage("waxseal");
int leftBorderX = topLeft.x+getInset().left;
int xWare = leftBorderX+100; // right aligned
int xCity = leftBorderX+110;
int prodCity = leftBorderX+160;
int prodChandler = leftBorderX+200;
int consCiticens = leftBorderX+270;
int consWorkshops = leftBorderX+330;
int consTotal = leftBorderX+380;
int yLineDiff = waxSeal.getHeight();
// Initialize the position relative to the frame
positions = new DialogPositions(titleHeight, yLineDiff, xWare, xCity, prodCity, prodChandler, consCiticens, consWorkshops, consTotal);
leftBorderX = getInset().left; // Use local coordinates
xWare = leftBorderX+100; // right aligned
// table header
gv = opPainter.createGlyphVector(g2d, "on a weekly basis", 18); // TODO externalize
length = (int) Math.rint(gv.getVisualBounds().getWidth());
x = ((bg.getWidth()-getInset().left-getInset().right)-length)/2;
g2d.drawGlyphVector(gv, x, y);
y += positions.lineHeight; // more space to the title
y += positions.lineHeight;
// Table
EWare[] wares = EWare.values();
for (EWare ware : wares) {
// Ware name
y += positions.lineHeight;
gv = opPainter.createGlyphVector(g2d, ware.getLocalDisplayName(), 18);
x = xWare-(int)Math.rint(gv.getVisualBounds().getWidth());
g2d.drawGlyphVector(gv, x, y);
// Amount available
// from city
// to city
}
// Footer buttons
y = bg.getHeight()-getInset().bottom-positions.lineHeight;
x = getInset().left+30;
int footerWidth = bg.getWidth()-getInset().left-getInset().right-2*30;
x += 3*footerWidth/4;
// close
g2d.drawImage(waxSeal, x,y-(int)(positions.lineHeight*0.8), null);
NamedPolygon polygon = new NamedPolygon("Close");
polygon.addPoint(topLeft.x+x, topLeft.y+y-(int)(positions.lineHeight*0.8));
polygon.addPoint(topLeft.x+x+waxSeal.getWidth(), topLeft.y+y-(int)(positions.lineHeight*0.8));
polygon.addPoint(topLeft.x+x+waxSeal.getWidth(), topLeft.y+y-(int)(positions.lineHeight*0.8)+waxSeal.getHeight());
polygon.addPoint(topLeft.x+x, topLeft.y+y-(int)(positions.lineHeight*0.8)+waxSeal.getHeight());
footerPolygons.add(polygon, new CloseAction(this));
g2d.setColor(new Color(0xEA,0xC1,0x17)); // Gold
gv = opPainter.createGlyphVector(g2d, "X", 18);
int xPadding = imageUtils.computeCenterAlignX(x, waxSeal.getWidth(), (int)gv.getVisualBounds().getWidth());
g2d.drawGlyphVector(gv, xPadding, y); // centeralign
} catch (FontFormatException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
return bg;
}
@Override
public void gameRender(Graphics gScr) {
Color oldColor = gScr.getColor();
super.gameRender(gScr);
gScr.setColor(Color.BLACK);
Graphics2D g2d = (Graphics2D) gScr;
try {
// Dialog title
int y = getBounds().y+getInset().top+10+(int)Math.rint(positions.titleHeigth*2/3);
final BufferedImage barrel = loader.getImage("barrel_icon");
final BufferedImage bale = loader.getImage("bale_icon");
// Sub title
y += positions.titleHeigth;
ICity cityModel = city.getCity();
y += (int)Math.rint(positions.titleHeigth*2/3);
// Table header
y += positions.lineHeight; // more space to the title
y += positions.lineHeight;
drawTableHeader(g2d, y);
// Table
EWare[] wares = EWare.values();
final DisplayImageDIResolver resolver = DisplayImageDIResolver.getInstance();
for (EWare ware : wares) {
// Ware name
y += positions.lineHeight;
// Available amount in the city
drawAvailableAmount(g2d,cityModel,ware, barrel, bale, y);
// city production
drawCityProduction(g2d,resolver,cityModel,ware, barrel, bale, y);
// chandler production
drawChandlerProduction(g2d,resolver,cityModel,ware,barrel,bale,y);
// consumtion citizens
drawCitizensConsumtion(g2d,resolver,cityModel,ware,barrel,bale,y);
// consumtion workshops
drawChandlerConsumption(g2d,resolver,cityModel,ware,barrel,bale,y);
// consumtion total
drawTotalConsumtion(g2d,resolver,cityModel,ware,barrel,bale,y);
} // end for wares
} catch (FontFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
gScr.setColor(oldColor);
}
/**
* Draw the total amount that is consumed of the ware
* @param g2d 2D graphics context used for drawing
* @param resolver Spring bean resolver
* @param city Reference to the city
* @param ware Reference to the ware
* @param barrel icon
* @param bale icon
* @param y position of from the top
* @throws IOException
* @throws FontFormatException
*/
private void drawTotalConsumtion(Graphics2D g2d,
DisplayImageDIResolver resolver, ICity cityModel, EWare ware,
BufferedImage barrel, BufferedImage bale, int y) throws FontFormatException, IOException {
BuildingProduction consumer = resolver.getBuildingProduction();
int amount = consumer.getTotalConsumtion(ware, cityModel);
amount += computeCitizenConsumtion(resolver, cityModel, ware);
drawWareAmount(g2d, ware, barrel, bale, y, amount, positions.consTotal);
}
/**
* Draw the amount the workshops consume of a ware
* @param g2d 2D graphics context used for drawing
* @param resolver Spring bean resolver
* @param city Reference to the city
* @param ware Reference to the ware
* @param barrel icon
* @param bale icon
* @param y position of from the top
* @throws IOException
* @throws FontFormatException
*/
private void drawChandlerConsumption(Graphics2D g2d,
DisplayImageDIResolver resolver, ICity cityModel, EWare ware,
BufferedImage barrel, BufferedImage bale, int y) throws FontFormatException, IOException {
BuildingProduction consumer = resolver.getBuildingProduction();
int amount = consumer.getTotalConsumtion(ware, cityModel);
drawWareAmount(g2d, ware, barrel, bale, y, amount, positions.consWorkshops);
}
/**
* Draw the amount the citizens consume
* @param g2d 2D graphics context used for drawing
* @param resolver Spring bean resolver
* @param city Reference to the city
* @param ware Reference to the ware
* @param barrel icon
* @param bale icon
* @param y position of from the top
* @throws IOException
* @throws FontFormatException
*/
private void drawCitizensConsumtion(Graphics2D g2d, DisplayImageDIResolver resolver, ICity cityModel,
EWare ware, BufferedImage barrel, BufferedImage bale, int y) throws FontFormatException, IOException {
int amount = computeCitizenConsumtion(resolver, cityModel, ware);
drawWareAmount(g2d, ware, barrel, bale, y, amount, positions.consCiticens);
}
/**
* Compute the amount that all the citizens consume
* @param resolver Spring bean resolver
* @param city Reference to the city
* @param ware Reference to the ware
* @return amount all the citizens consume of that ware
*/
private int computeCitizenConsumtion(DisplayImageDIResolver resolver,
ICity city, EWare ware) {
PopulationConsume consumer = resolver.getPolulanceConsumtion();
double amount = consumer.getNeed(ware, EPopulationClass.POOR, city.getPopulation(EPopulationClass.POOR));
amount += consumer.getNeed(ware, EPopulationClass.MEDIUM, city.getPopulation(EPopulationClass.MEDIUM));
amount += consumer.getNeed(ware, EPopulationClass.RICH, city.getPopulation(EPopulationClass.RICH));
int value = (int) Math.rint(amount);
return value;
}
/**
* Draw the amount all the chandlers produce
* @param resolver Spring bean resolver
* @param g2d 2D graphics context used for drawing
* @param city Reference to the city
* @param ware Reference to the ware
* @param barrel icon
* @param bale icon
* @param y position of from the top
* @throws IOException
* @throws FontFormatException
*/
private void drawChandlerProduction(Graphics2D g2d, DisplayImageDIResolver resolver, ICity cityModel,
EWare ware, BufferedImage barrel, BufferedImage bale, int y) throws FontFormatException, IOException {
BuildingProduction producer = resolver.getBuildingProduction();
int amount = producer.getTotalProduction(ware, cityModel);
drawWareAmount(g2d, ware, barrel, bale, y, amount, positions.prodChandler);
}
/**
* Draw the amount the city produces per week
* @param g2d 2D graphics context used for drawing
* @param resolver Spring bean resolver
* @param city Reference to the city
* @param ware Reference to the ware
* @param barrel icon
* @param bale icon
* @param y position of from the top
* @throws IOException
* @throws FontFormatException
*/
private void drawCityProduction(Graphics2D g2d, DisplayImageDIResolver resolver, ICity city,
EWare ware, BufferedImage barrel, BufferedImage bale, int y) throws FontFormatException, IOException {
IWare[] effective = city.getEffectiveProduction();
IWare[] ineffective = city.getIneffectiveProduction();
int amount=0;
if (contains(effective, ware)){
CityProduction producer = resolver.getCityProduction();
amount = producer.getEfficientProduction(ware);
} else if (contains(ineffective, ware)){
CityProduction producer = resolver.getCityProduction();
amount = producer.getInefficientProduction(ware);
}
drawWareAmount(g2d, ware, barrel, bale, y, amount, positions.prodCity);
}
/**
* Optionally draw the amoount of wares (if positive) together with the correct icon
* @param g2d
* @param ware
* @param barrel
* @param bale
* @param y
* @param amount
* @param xPadding
* @throws FontFormatException
* @throws IOException
*/
private void drawWareAmount(Graphics2D g2d, EWare ware,
BufferedImage barrel, BufferedImage bale, int y, int amount,
int xPadding) throws FontFormatException, IOException {
if (amount>0){
GlyphVector gv = opPainter.createGlyphVector(g2d, String.valueOf(amount), 18);
g2d.drawGlyphVector(gv, xPadding, y);
// draw barrel or burden
if (ware.getSizeAsBarrels()==1){
// barrel
g2d.drawImage(barrel, (int)(xPadding+gv.getVisualBounds().getWidth())+5, y-positions.lineHeight*2/3, null);
} else {
g2d.drawImage(bale, (int)(xPadding+gv.getVisualBounds().getWidth())+5, y-positions.lineHeight*2/3, null);
}
}
}
/**
* check if the array contains the item
* @param array
* @param item
* @return
*/
private boolean contains(IWare[] array, IWare item){
for (IWare ware : array) {
if (ware==item) return true;
}
return false;
}
/**
* Draw the available amount (second column). Available refers either to city or the storage based on
* the current dialog type.
* @param g2d 2D graphics context used for drawing
* @param city Reference to the city
* @param ware Reference to the ware
* @param barrel icon
* @param bale icon
* @param y position of from the top
* @return the available amount
* @throws FontFormatException Error while creating a font
* @throws IOException Error while reading a resource
*/
private int drawAvailableAmount(Graphics2D g2d, ICity city,IWare ware,BufferedImage barrel, BufferedImage bale,int y) throws FontFormatException, IOException{
AmountablePrice available = city.getWare(ware);
int availableAmount = available.getAmount();
int value = availableAmount; // amount available
int xPadding = positions.xCity;
drawWareAmount(g2d, (EWare) ware, barrel, bale, y, value, xPadding);
return availableAmount;
}
/**
* This class holds the positions where different elements are
* placed on the dialog.
* @author Andi Hotz, (c) Sahits GmbH, 2011
* Created on Dec 9, 2011
*
*/
private static class DialogPositions{
private final double titleHeigth;
private final int lineHeight;
private final int xWare;
private final int xCity;
private final int prodCity;
private final int prodChandler;
private final int consCiticens;
private final int consWorkshops;
private final int consTotal;
public DialogPositions(double titleHeigth, int lineHeight, int xWare,
int xCity, int prodCity, int prodChandler, int consCiticens,
int consWorkshops, int consTotal) {
super();
this.titleHeigth = titleHeigth;
this.lineHeight = lineHeight;
this.xWare = xWare;
this.xCity = xCity;
this.prodCity = prodCity;
this.prodChandler = prodChandler;
this.consCiticens = consCiticens;
this.consWorkshops = consWorkshops;
this.consTotal = consTotal;
}
}
}