/**
 * MegaMek - Copyright (C) 2000-2002 Ben Mazur (bmazur@sev.org)
 * 
 *  This program is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU General Public License as published by the Free 
 *  Software Foundation; either version 2 of the License, or (at your option) 
 *  any later version.
 * 
 *  This program is distributed in the hope that it will be useful, but 
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 *  for more details.
 */

package megamek.client.ui.AWT.widget;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Polygon;
import java.util.Vector;

import megamek.client.ui.Messages;
import megamek.client.ui.AWT.GUIPreferences;
import megamek.common.Entity;
import megamek.common.Mech;

/**
 * Very cumbersome class that handles set of polygonal areas and labels for
 * PicMap component to represent single mech unit in MechDisplay
 */

public class QuadMapSet implements DisplayMapSet {

    private static final String IMAGE_DIR = "data/images/widgets";

    // Because of keeping all areas of single type in one array
    // some index offset values required
    private static final int REAR_AREA_OFFSET = 7;
    private static final int INT_STRUCTURE_OFFSET = 11;

    // Array of polygonal areas - parts of mech body.
    private PMSimplePolygonArea[] areas = new PMSimplePolygonArea[19];
    // Array of fixed labels - short names of body parts
    private PMSimpleLabel[] labels = new PMSimpleLabel[19];
    // Array of value labels to show armor and IS values
    private PMValueLabel[] vLabels = new PMValueLabel[20];
    // Heat control area
    private PMPicPolygonalArea heatHotArea;
    // Set of Background Drawers
    private Vector<BackGroundDrawer> bgDrawers = new Vector<BackGroundDrawer>();
    // Main areas group that keeps everything in itself and is passed to PicMap
    // component
    private PMAreasGroup content = new PMAreasGroup();
    // Reference to Component class (need to manage images and fonts)
    private Component comp;

    // Points for build hot areas (may be too heavy, think of to load from
    // exteranl file)
    // Mek armor - Front
    private Polygon rightArm = new Polygon(new int[] { 102, 102, 100, 95, 95,
            100, 110, 120, 120, 125 }, new int[] { 120, 70, 65, 65, 50, 55, 55,
            65, 115, 120 }, 10);
    private Polygon leftArm = new Polygon(new int[] { 0, 5, 5, 15, 25, 30, 30,
            25, 23, 23 },
            new int[] { 120, 115, 65, 55, 55, 50, 65, 65, 70, 120 }, 10);
    private Polygon head = new Polygon(new int[] { 50, 50, 55, 70, 75, 75 },
            new int[] { 40, 25, 20, 20, 25, 40 }, 6);
    private Polygon centralTorso = new Polygon(new int[] { 50, 50, 75, 75 },
            new int[] { 80, 40, 40, 80 }, 4);
    private Polygon leftTorso = new Polygon(
            new int[] { 50, 35, 30, 30, 35, 50 }, new int[] { 80, 80, 75, 45,
                    40, 40 }, 6);
    private Polygon rightTorso = new Polygon(
            new int[] { 75, 75, 90, 95, 95, 90 }, new int[] { 80, 40, 40, 45,
                    75, 80 }, 6);
    private Polygon leftLeg = new Polygon(new int[] { 30, 30, 35, 50, 50, 55 },
            new int[] { 120, 85, 80, 80, 115, 120 }, 6);
    private Polygon rightLeg = new Polygon(
            new int[] { 70, 75, 75, 90, 95, 95 }, new int[] { 120, 115, 80, 80,
                    85, 120 }, 6);

    // Mek Armor - Rear
    private Polygon rearLeftTorso = new Polygon(new int[] { 142, 142, 148, 139,
            123, 123, 142 }, new int[] { 14, 43, 76, 76, 44, 17, 14 }, 7);
    private Polygon rearCentralTorso = new Polygon(new int[] { 142, 148, 162,
            168, 168, 142 }, new int[] { 44, 76, 76, 44, 14, 14 }, 6);
    private Polygon rearRightTorso = new Polygon(new int[] { 168, 168, 162,
            171, 187, 187, 168 }, new int[] { 14, 43, 76, 76, 44, 17, 14 }, 7);

    // Internal Structure
    private Polygon inStRightArm = new Polygon(new int[] { 102, 102, 100, 95,
            95, 100, 110, 120, 120, 125 }, new int[] { 112 + 120, 112 + 70,
            112 + 65, 112 + 65, 112 + 50, 112 + 55, 112 + 55, 112 + 65,
            112 + 115, 112 + 120 }, 10);
    private Polygon inStLeftArm = new Polygon(new int[] { 0, 5, 5, 15, 25, 30,
            30, 25, 23, 23 }, new int[] { 112 + 120, 112 + 115, 112 + 65,
            112 + 55, 112 + 55, 112 + 50, 112 + 65, 112 + 65, 112 + 70,
            112 + 120 }, 10);
    private Polygon intStHead = new Polygon(
            new int[] { 50, 50, 55, 70, 75, 75 }, new int[] { 112 + 40,
                    112 + 25, 112 + 20, 112 + 20, 112 + 25, 112 + 40 }, 6);
    private Polygon inStCentralTorso = new Polygon(
            new int[] { 50, 50, 75, 75 }, new int[] { 112 + 80, 112 + 40,
                    112 + 40, 112 + 80 }, 4);
    private Polygon inStLeftTorso = new Polygon(new int[] { 50, 35, 30, 30, 35,
            50 }, new int[] { 112 + 80, 112 + 80, 112 + 75, 112 + 45, 112 + 40,
            112 + 40 }, 6);
    private Polygon inStRightTorso = new Polygon(new int[] { 75, 75, 90, 95,
            95, 90 }, new int[] { 112 + 80, 112 + 40, 112 + 40, 112 + 45,
            112 + 75, 112 + 80 }, 6);
    private Polygon inStLeftLeg = new Polygon(new int[] { 30, 30, 35, 50, 50,
            55 }, new int[] { 112 + 120, 112 + 85, 112 + 80, 112 + 80,
            112 + 115, 112 + 120 }, 6);
    private Polygon inStRightLeg = new Polygon(new int[] { 70, 75, 75, 90, 95,
            95 }, new int[] { 112 + 120, 112 + 115, 112 + 80, 112 + 80,
            112 + 85, 112 + 120 }, 6);

    // Heat control
    private Polygon heatControl = new Polygon(new int[] { 149, 159, 159, 149 },
            new int[] { 100, 100, 220, 220 }, 4);

    private Image heatImage;

    private static final Font FONT_LABEL = new Font(
            "SansSerif", Font.PLAIN, GUIPreferences.getInstance().getInt("AdvancedMechDisplayArmorSmallFontSize")); //$NON-NLS-1$
    private static final Font FONT_VALUE = new Font(
            "SansSerif", Font.PLAIN, GUIPreferences.getInstance().getInt("AdvancedMechDisplayArmorLargeFontSize")); //$NON-NLS-1$

    public QuadMapSet(Component c) {
        comp = c;
        setAreas();
        setLabels();
        setGroups();
        setBackGround();
    }

    public PMAreasGroup getContentGroup() {
        return content;
    }

    public Vector<BackGroundDrawer> getBackgroundDrawers() {
        return bgDrawers;
    }

    public void setEntity(Entity e) {
        Mech m = (Mech) e;
        boolean mtHeat = false;
        if (e.getGame() != null
                && e.getGame().getOptions().booleanOption("tacops_heat")) {
            mtHeat = true;
        }
        int a = 1;
        int a0 = 1;
        for (int i = 0; i < m.locations(); i++) {
            a = m.getArmor(i);
            a0 = m.getOArmor(i);
            vLabels[i].setValue(m.getArmorString(i));
            WidgetUtils.setAreaColor(areas[i], vLabels[i], (double) a
                    / (double) a0);
            if (m.hasRearArmor(i)) {
                a = m.getArmor(i, true);
                a0 = m.getOArmor(i, true);
                vLabels[i + REAR_AREA_OFFSET].setValue(m
                        .getArmorString(i, true));
                WidgetUtils.setAreaColor(areas[i + REAR_AREA_OFFSET], vLabels[i
                        + REAR_AREA_OFFSET], (double) a / (double) a0);
            }
            a = m.getInternal(i);
            a0 = m.getOInternal(i);
            vLabels[i + INT_STRUCTURE_OFFSET].setValue(m.getInternalString(i));
            WidgetUtils.setAreaColor(areas[i + INT_STRUCTURE_OFFSET], vLabels[i
                    + INT_STRUCTURE_OFFSET], (double) a / (double) a0);
        }

        // heat
        vLabels[19].setValue(Integer.toString(m.heat));
        drawHeatControl(m.heat, mtHeat);
    }

    private void setAreas() {
        areas[Mech.LOC_HEAD] = new PMSimplePolygonArea(head);
        areas[Mech.LOC_CT] = new PMSimplePolygonArea(centralTorso);
        areas[Mech.LOC_RT] = new PMSimplePolygonArea(rightTorso);
        areas[Mech.LOC_LT] = new PMSimplePolygonArea(leftTorso);
        areas[Mech.LOC_RARM] = new PMSimplePolygonArea(rightArm);
        areas[Mech.LOC_LARM] = new PMSimplePolygonArea(leftArm);
        areas[Mech.LOC_RLEG] = new PMSimplePolygonArea(rightLeg);
        areas[Mech.LOC_LLEG] = new PMSimplePolygonArea(leftLeg);
        areas[REAR_AREA_OFFSET + Mech.LOC_CT] = new PMSimplePolygonArea(
                rearCentralTorso);
        areas[REAR_AREA_OFFSET + Mech.LOC_RT] = new PMSimplePolygonArea(
                rearRightTorso);
        areas[REAR_AREA_OFFSET + Mech.LOC_LT] = new PMSimplePolygonArea(
                rearLeftTorso);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_HEAD] = new PMSimplePolygonArea(
                intStHead);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_CT] = new PMSimplePolygonArea(
                inStCentralTorso);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_RT] = new PMSimplePolygonArea(
                inStRightTorso);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_LT] = new PMSimplePolygonArea(
                inStLeftTorso);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_RARM] = new PMSimplePolygonArea(
                inStRightArm);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_LARM] = new PMSimplePolygonArea(
                inStLeftArm);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_RLEG] = new PMSimplePolygonArea(
                inStRightLeg);
        areas[INT_STRUCTURE_OFFSET + Mech.LOC_LLEG] = new PMSimplePolygonArea(
                inStLeftLeg);
        heatImage = comp.createImage(10, 120);
        drawHeatControl(0);
        heatHotArea = new PMPicPolygonalArea(heatControl, heatImage);
    }

    private void setLabels() {
        FontMetrics fm = comp.getFontMetrics(FONT_LABEL);

        // Labels for Front view
        labels[Mech.LOC_HEAD] = WidgetUtils.createLabel(Messages
                .getString("MechMapSet.l_H"), fm, Color.black, 58, 29); //$NON-NLS-1$
        labels[Mech.LOC_LARM] = WidgetUtils.createLabel(Messages
                .getString("QuadMapSet.L_LA"), fm, Color.black, 14, 69); //$NON-NLS-1$
        labels[Mech.LOC_LT] = WidgetUtils.createLabel(Messages
                .getString("MechMapSet.l_LT"), fm, Color.black, 41, 52); //$NON-NLS-1$
        labels[Mech.LOC_CT] = WidgetUtils.createLabel(Messages
                .getString("MechMapSet.l_CT"), fm, Color.black, 62, 45); //$NON-NLS-1$
        labels[Mech.LOC_RT] = WidgetUtils.createLabel(Messages
                .getString("MechMapSet.l_RT"), fm, Color.black, 84, 52); //$NON-NLS-1$
        labels[Mech.LOC_RARM] = WidgetUtils.createLabel(Messages
                .getString("QuadMapSet.L_RA"), fm, Color.black, 111, 69); //$NON-NLS-1$
        labels[Mech.LOC_LLEG] = WidgetUtils.createLabel(Messages
                .getString("QuadMapSet.L_LL"), fm, Color.black, 39, 87); //$NON-NLS-1$
        labels[Mech.LOC_RLEG] = WidgetUtils.createLabel(Messages
                .getString("QuadMapSet.L_RL"), fm, Color.black, 85, 87); //$NON-NLS-1$
        // Labels for Back view
        labels[REAR_AREA_OFFSET + Mech.LOC_LT] = WidgetUtils
                .createLabel(
                        Messages.getString("MechMapSet.l_LT"), fm, Color.black, 133, 39); //$NON-NLS-1$
        labels[REAR_AREA_OFFSET + Mech.LOC_CT] = WidgetUtils
                .createLabel(
                        Messages.getString("MechMapSet.l_CT"), fm, Color.black, 156, 25); //$NON-NLS-1$
        labels[REAR_AREA_OFFSET + Mech.LOC_RT] = WidgetUtils
                .createLabel(
                        Messages.getString("MechMapSet.l_RT"), fm, Color.black, 178, 39); //$NON-NLS-1$
        // Labels for Internal Structure
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_HEAD] = WidgetUtils.createLabel(
                Messages.getString("MechMapSet.l_H"), fm, Color.black, 63, 130); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_LARM] = WidgetUtils
                .createLabel(
                        Messages.getString("QuadMapSet.L_LA"), fm, Color.black, 14, 179); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_LT] = WidgetUtils
                .createLabel(
                        Messages.getString("MechMapSet.l_LT"), fm, Color.black, 42, 166); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_CT] = WidgetUtils
                .createLabel(
                        Messages.getString("MechMapSet.L_CT"), fm, Color.black, 63, 160); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_RT] = WidgetUtils
                .createLabel(
                        Messages.getString("MechMapSet.l_RT"), fm, Color.black, 85, 166); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_RARM] = WidgetUtils
                .createLabel(
                        Messages.getString("QuadMapSet.L_RA"), fm, Color.black, 111, 179); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_LLEG] = WidgetUtils
                .createLabel(
                        Messages.getString("QuadMapSet.L_LL"), fm, Color.black, 39, 200); //$NON-NLS-1$
        labels[INT_STRUCTURE_OFFSET + Mech.LOC_RLEG] = WidgetUtils
                .createLabel(
                        Messages.getString("QuadMapSet.L_RL"), fm, Color.black, 85, 200); //$NON-NLS-1$

        // Value labels for all parts of mek
        // front
        fm = comp.getFontMetrics(FONT_VALUE);
        vLabels[Mech.LOC_HEAD] = WidgetUtils.createValueLabel(68, 30, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_LARM] = WidgetUtils.createValueLabel(13, 82, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_LT] = WidgetUtils.createValueLabel(40, 66, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_CT] = WidgetUtils.createValueLabel(62, 60, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_RT] = WidgetUtils.createValueLabel(85, 66, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_RARM] = WidgetUtils.createValueLabel(112, 82, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_LLEG] = WidgetUtils.createValueLabel(39, 103, "", fm); //$NON-NLS-1$
        vLabels[Mech.LOC_RLEG] = WidgetUtils.createValueLabel(85, 103, "", fm); //$NON-NLS-1$

        // back
        vLabels[REAR_AREA_OFFSET + Mech.LOC_LT] = WidgetUtils.createValueLabel(
                132, 28, "", fm); //$NON-NLS-1$
        vLabels[REAR_AREA_OFFSET + Mech.LOC_CT] = WidgetUtils.createValueLabel(
                156, 39, "", fm); //$NON-NLS-1$
        vLabels[REAR_AREA_OFFSET + Mech.LOC_RT] = WidgetUtils.createValueLabel(
                177, 28, "", fm); //$NON-NLS-1$

        // Internal structure
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_HEAD] = WidgetUtils
                .createValueLabel(63, 142, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_LARM] = WidgetUtils
                .createValueLabel(15, 192, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_LT] = WidgetUtils
                .createValueLabel(42, 180, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_CT] = WidgetUtils
                .createValueLabel(63, 175, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_RT] = WidgetUtils
                .createValueLabel(85, 180, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_RARM] = WidgetUtils
                .createValueLabel(111, 192, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_LLEG] = WidgetUtils
                .createValueLabel(39, 215, "", fm); //$NON-NLS-1$
        vLabels[INT_STRUCTURE_OFFSET + Mech.LOC_RLEG] = WidgetUtils
                .createValueLabel(85, 215, "", fm); //$NON-NLS-1$
        // heat
        vLabels[19] = WidgetUtils.createValueLabel(155, 90, "", fm); //$NON-NLS-1$
    }

    private void setGroups() {
        // Have to remove it later
        PMAreasGroup frontArmor = new PMAreasGroup();
        PMAreasGroup rearArmor = new PMAreasGroup();
        PMAreasGroup intStructure = new PMAreasGroup();
        PMAreasGroup heat = new PMAreasGroup();

        for (int i = 0; i < 8; i++) {
            frontArmor.addArea(areas[i]);
            frontArmor.addArea(labels[i]);
            frontArmor.addArea(vLabels[i]);
        }

        for (int i = 0; i < 3; i++) {
            rearArmor.addArea(areas[8 + i]);
            rearArmor.addArea(labels[8 + i]);
            rearArmor.addArea(vLabels[8 + i]);
        }

        for (int i = 0; i < 8; i++) {
            intStructure.addArea(areas[11 + i]);
            intStructure.addArea(labels[11 + i]);
            intStructure.addArea(vLabels[11 + i]);
        }

        heat.addArea(heatHotArea);
        heat.addArea(vLabels[19]);

        frontArmor.translate(7, 18);
        rearArmor.translate(19, 20);
        intStructure.translate(6, 42);
        heat.translate(20, 52);

        // This have to be left
        for (int i = 0; i < 19; i++) {
            content.addArea(areas[i]);
            content.addArea(labels[i]);
            content.addArea(vLabels[i]);
        }

        content.addArea(heatHotArea);
        content.addArea(vLabels[19]);
    }

    private void setBackGround() {
        Image tile = comp.getToolkit().getImage(IMAGE_DIR + "/tile.gif"); //$NON-NLS-1$
        PMUtil.setImage(tile, comp);
        int b = BackGroundDrawer.TILING_BOTH;
        bgDrawers.addElement(new BackGroundDrawer(tile, b));
        tile = comp.getToolkit().getImage(IMAGE_DIR + "/bg_mech.gif"); //$NON-NLS-1$
        PMUtil.setImage(tile, comp);
        b = BackGroundDrawer.NO_TILING | BackGroundDrawer.VALIGN_CENTER
                | BackGroundDrawer.HALIGN_CENTER;
        BackGroundDrawer bgd = new BackGroundDrawer(tile, b);
        bgDrawers.addElement(bgd);
    }

    private void drawHeatControl(int t) {
        drawHeatControl(t, false);
    }

    private void drawHeatControl(int t, boolean mtHeat) {
        int y = 0;
        int maxHeat, steps;
        if (mtHeat) {
            maxHeat = 50;
            steps = 2;
        } else {
            maxHeat = 30;
            steps = 4;
        }
        Graphics g = heatImage.getGraphics();
        for (int i = 0; i < maxHeat; i++) {
            y = 120 - (i + 1) * steps;
            if (i < t) {
                g.setColor(Color.red);
            } else {
                g.setColor(Color.lightGray);
            }
            g.fillRect(0, y, 10, steps);
            g.setColor(Color.black);
            g.drawRect(0, y, 10, steps);
        }
    }
}
