/*
 * Copyright (C) 1997-2001 Id Software, Inc.
 * 
 * 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.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package lwjake2.game;

import lwjake2.Defines;
import lwjake2.qcommon.Com;
import lwjake2.util.Lib;
import lwjake2.util.Math3D;
import lwjake2.util.Vargs;

public class PlayerHud {

    /*
     * ======================================================================
     * 
     * INTERMISSION
     * 
     * ======================================================================
     */

    public static void MoveClientToIntermission(edict_t ent) {
        if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0)
            ent.client.showscores = true;
        Math3D.VectorCopy(GameBase.level.intermission_origin, ent.s.origin);
        ent.client.ps.pmove.origin[0] = (short) (GameBase.level.intermission_origin[0] * 8);
        ent.client.ps.pmove.origin[1] = (short) (GameBase.level.intermission_origin[1] * 8);
        ent.client.ps.pmove.origin[2] = (short) (GameBase.level.intermission_origin[2] * 8);
        Math3D.VectorCopy(GameBase.level.intermission_angle,
                ent.client.ps.viewangles);
        ent.client.ps.pmove.pm_type = Defines.PM_FREEZE;
        ent.client.ps.gunindex = 0;
        ent.client.ps.blend[3] = 0;
        ent.client.ps.rdflags &= ~Defines.RDF_UNDERWATER;

        // clean up powerup info
        ent.client.quad_framenum = 0;
        ent.client.invincible_framenum = 0;
        ent.client.breather_framenum = 0;
        ent.client.enviro_framenum = 0;
        ent.client.grenade_blew_up = false;
        ent.client.grenade_time = 0;

        ent.viewheight = 0;
        ent.s.modelindex = 0;
        ent.s.modelindex2 = 0;
        ent.s.modelindex3 = 0;
        ent.s.modelindex = 0;
        ent.s.effects = 0;
        ent.s.sound = 0;
        ent.solid = Defines.SOLID_NOT;

        // add the layout

        if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) {
            DeathmatchScoreboardMessage(ent, null);
            GameBase.gi.unicast(ent, true);
        }

    }

    public static void BeginIntermission(edict_t targ) {
        int i, n;
        edict_t ent, client;

        if (GameBase.level.intermissiontime != 0)
            return; // already activated

        GameBase.game.autosaved = false;

        // respawn any dead clients
        for (i = 0; i < GameBase.maxclients.value; i++) {
            client = GameBase.g_edicts[1 + i];
            if (!client.inuse)
                continue;
            if (client.health <= 0)
                PlayerClient.respawn(client);
        }

        GameBase.level.intermissiontime = GameBase.level.time;
        GameBase.level.changemap = targ.map;

        if (GameBase.level.changemap.indexOf('*') > -1) {
            if (GameBase.coop.value != 0) {
                for (i = 0; i < GameBase.maxclients.value; i++) {
                    client = GameBase.g_edicts[1 + i];
                    if (!client.inuse)
                        continue;
                    // strip players of all keys between units
                    for (n = 1; n < GameItemList.itemlist.length; n++) {
                        // null pointer exception fixed. (RST) 
                        if (GameItemList.itemlist[n] != null)
                            if ((GameItemList.itemlist[n].flags & Defines.IT_KEY) != 0)
                                client.client.pers.inventory[n] = 0;
                    }
                }
            }
        } else {
            if (0 == GameBase.deathmatch.value) {
                GameBase.level.exitintermission = true; // go immediately to the
                                                        // next level
                return;
            }
        }

        GameBase.level.exitintermission = false;

        // find an intermission spot
        ent = GameBase.G_FindEdict(null, GameBase.findByClass,
                "info_player_intermission");
        if (ent == null) { // the map creator forgot to put in an intermission
                           // point...
            ent = GameBase.G_FindEdict(null, GameBase.findByClass,
                    "info_player_start");
            if (ent == null)
                ent = GameBase.G_FindEdict(null, GameBase.findByClass,
                        "info_player_deathmatch");
        } else { // chose one of four spots
            i = Lib.rand() & 3;
            EdictIterator es = null;

            while (i-- > 0) {
                es = GameBase.G_Find(es, GameBase.findByClass,
                        "info_player_intermission");

                if (es == null) // wrap around the list
                    continue;
                ent = es.o;
            }
        }

        Math3D.VectorCopy(ent.s.origin, GameBase.level.intermission_origin);
        Math3D.VectorCopy(ent.s.angles, GameBase.level.intermission_angle);

        // move all clients to the intermission point
        for (i = 0; i < GameBase.maxclients.value; i++) {
            client = GameBase.g_edicts[1 + i];
            if (!client.inuse)
                continue;
            MoveClientToIntermission(client);
        }
    }

    /*
     * ================== 
     * DeathmatchScoreboardMessage
     * ==================
     */
    public static void DeathmatchScoreboardMessage(edict_t ent, edict_t killer) {
        StringBuffer string = new StringBuffer(1400);

        int i, j, k;
        int sorted[] = new int[Defines.MAX_CLIENTS];
        int sortedscores[] = new int[Defines.MAX_CLIENTS];
        int score, total;
        int x, y;
        gclient_t cl;
        edict_t cl_ent;
        String tag;

        // sort the clients by score
        total = 0;
        for (i = 0; i < GameBase.game.maxclients; i++) {
            cl_ent = GameBase.g_edicts[1 + i];
            if (!cl_ent.inuse || GameBase.game.clients[i].resp.spectator)
                continue;
            score = GameBase.game.clients[i].resp.score;
            for (j = 0; j < total; j++) {
                if (score > sortedscores[j])
                    break;
            }
            for (k = total; k > j; k--) {
                sorted[k] = sorted[k - 1];
                sortedscores[k] = sortedscores[k - 1];
            }
            sorted[j] = i;
            sortedscores[j] = score;
            total++;
        }

        // print level name and exit rules

        // add the clients in sorted order
        if (total > 12)
            total = 12;
        
        for (i = 0; i < total; i++) {
            cl = GameBase.game.clients[sorted[i]];
            cl_ent = GameBase.g_edicts[1 + sorted[i]];

            GameBase.gi.imageindex("i_fixme");
            x = (i >= 6) ? 160 : 0;
            y = 32 + 32 * (i % 6);

            // add a dogtag
            if (cl_ent == ent)
                tag = "tag1";
            else if (cl_ent == killer)
                tag = "tag2";
            else
                tag = null;

            if (tag != null) {
                string.append("xv ").append(x + 32).append(" yv ").append(y)
                        .append(" picn ").append(tag);
            }

            // send the layout
            string
                    .append(" client ")
                    .append(x)
                    .append(" ")
                    .append(y)
                    .append(" ")
                    .append(sorted[i])
                    .append(" ")
                    .append(cl.resp.score)
                    .append(" ")
                    .append(cl.ping)
                    .append(" ")
                    .append(
                            (GameBase.level.framenum - cl.resp.enterframe) / 600);           
        }

        GameBase.gi.WriteByte(Defines.svc_layout);
        GameBase.gi.WriteString(string.toString());
    }

    /*
     * ================== 
     * DeathmatchScoreboard
     * 
     * Draw instead of help message. Note that it isn't that hard to overflow
     * the 1400 byte message limit! 
     * ==================
     */
    public static void DeathmatchScoreboard(edict_t ent) {
        DeathmatchScoreboardMessage(ent, ent.enemy);
        GameBase.gi.unicast(ent, true);
    }

    /*
     * ================== 
     * Cmd_Score_f
     * 
     * Display the scoreboard 
     * ==================
     */
    public static void Cmd_Score_f(edict_t ent) {
        ent.client.showinventory = false;
        ent.client.showhelp = false;

        if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value)
            return;

        if (ent.client.showscores) {
            ent.client.showscores = false;
            return;
        }

        ent.client.showscores = true;
        DeathmatchScoreboard(ent);
    }

    //=======================================================================

    /*
     * =============== 
     * G_SetStats 
     * ===============
     */
    public static void G_SetStats(edict_t ent) {
        gitem_t item;
        int index, cells = 0;
        int power_armor_type;

        //
        // health
        //
        ent.client.ps.stats[Defines.STAT_HEALTH_ICON] = (short) GameBase.level.pic_health;
        ent.client.ps.stats[Defines.STAT_HEALTH] = (short) ent.health;

        //
        // ammo
        //
        if (0 == ent.client.ammo_index /*
                                        * ||
                                        * !ent.client.pers.inventory[ent.client.ammo_index]
                                        */
        ) {
            ent.client.ps.stats[Defines.STAT_AMMO_ICON] = 0;
            ent.client.ps.stats[Defines.STAT_AMMO] = 0;
        } else {
            item = GameItemList.itemlist[ent.client.ammo_index];
            ent.client.ps.stats[Defines.STAT_AMMO_ICON] = (short) GameBase.gi
                    .imageindex(item.icon);
            ent.client.ps.stats[Defines.STAT_AMMO] = (short) ent.client.pers.inventory[ent.client.ammo_index];
        }

        //
        // armor
        //
        power_armor_type = GameItems.PowerArmorType(ent);
        if (power_armor_type != 0) {
            cells = ent.client.pers.inventory[GameItems.ITEM_INDEX(GameItems
                    .FindItem("cells"))];
            if (cells == 0) { // ran out of cells for power armor
                ent.flags &= ~Defines.FL_POWER_ARMOR;
                GameBase.gi
                        .sound(ent, Defines.CHAN_ITEM, GameBase.gi
                                .soundindex("misc/power2.wav"), 1,
                                Defines.ATTN_NORM, 0);
                power_armor_type = 0;
                ;
            }
        }

        index = GameItems.ArmorIndex(ent);
        if (power_armor_type != 0
                && (0 == index || 0 != (GameBase.level.framenum & 8))) { // flash
                                                                         // between
                                                                         // power
                                                                         // armor
                                                                         // and
                                                                         // other
                                                                         // armor
                                                                         // icon
            ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi
                    .imageindex("i_powershield");
            ent.client.ps.stats[Defines.STAT_ARMOR] = (short) cells;
        } else if (index != 0) {
            item = GameItems.GetItemByIndex(index);
            ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi
                    .imageindex(item.icon);
            ent.client.ps.stats[Defines.STAT_ARMOR] = (short) ent.client.pers.inventory[index];
        } else {
            ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = 0;
            ent.client.ps.stats[Defines.STAT_ARMOR] = 0;
        }

        //
        // pickup message
        //
        if (GameBase.level.time > ent.client.pickup_msg_time) {
            ent.client.ps.stats[Defines.STAT_PICKUP_ICON] = 0;
            ent.client.ps.stats[Defines.STAT_PICKUP_STRING] = 0;
        }

        //
        // timers
        //
        if (ent.client.quad_framenum > GameBase.level.framenum) {
            ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
                    .imageindex("p_quad");
            ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.quad_framenum - GameBase.level.framenum) / 10);
        } else if (ent.client.invincible_framenum > GameBase.level.framenum) {
            ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
                    .imageindex("p_invulnerability");
            ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.invincible_framenum - GameBase.level.framenum) / 10);
        } else if (ent.client.enviro_framenum > GameBase.level.framenum) {
            ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
                    .imageindex("p_envirosuit");
            ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.enviro_framenum - GameBase.level.framenum) / 10);
        } else if (ent.client.breather_framenum > GameBase.level.framenum) {
            ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi
                    .imageindex("p_rebreather");
            ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.breather_framenum - GameBase.level.framenum) / 10);
        } else {
            ent.client.ps.stats[Defines.STAT_TIMER_ICON] = 0;
            ent.client.ps.stats[Defines.STAT_TIMER] = 0;
        }

        //
        // selected item
        //
        // bugfix rst
        if (ent.client.pers.selected_item <= 0)
            ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = 0;
        else
            ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = (short) GameBase.gi
                    .imageindex(GameItemList.itemlist[ent.client.pers.selected_item].icon);

        ent.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) ent.client.pers.selected_item;

        //
        // layouts
        //
        ent.client.ps.stats[Defines.STAT_LAYOUTS] = 0;

        if (GameBase.deathmatch.value != 0) {
            if (ent.client.pers.health <= 0
                    || GameBase.level.intermissiontime != 0
                    || ent.client.showscores)
                ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1;
            if (ent.client.showinventory && ent.client.pers.health > 0)
                ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2;
        } else {
            if (ent.client.showscores || ent.client.showhelp)
                ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1;
            if (ent.client.showinventory && ent.client.pers.health > 0)
                ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2;
        }

        //
        // frags
        //
        ent.client.ps.stats[Defines.STAT_FRAGS] = (short) ent.client.resp.score;

        //
        // help icon / current weapon if not shown
        //
        if (ent.client.pers.helpchanged != 0
                && (GameBase.level.framenum & 8) != 0)
            ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi
                    .imageindex("i_help");
        else if ((ent.client.pers.hand == Defines.CENTER_HANDED || ent.client.ps.fov > 91)
                && ent.client.pers.weapon != null)
            ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi
                    .imageindex(ent.client.pers.weapon.icon);
        else
            ent.client.ps.stats[Defines.STAT_HELPICON] = 0;

        ent.client.ps.stats[Defines.STAT_SPECTATOR] = 0;
    }

    /*
     * =============== 
     * G_CheckChaseStats 
     * ===============
     */
    public static void G_CheckChaseStats(edict_t ent) {
        int i;
        gclient_t cl;

        for (i = 1; i <= GameBase.maxclients.value; i++) {
            cl = GameBase.g_edicts[i].client;
            if (!GameBase.g_edicts[i].inuse || cl.chase_target != ent)
                continue;
            //memcpy(cl.ps.stats, ent.client.ps.stats, sizeof(cl.ps.stats));
            System.arraycopy(ent.client.ps.stats, 0, cl.ps.stats, 0,
                    Defines.MAX_STATS);

            G_SetSpectatorStats(GameBase.g_edicts[i]);
        }
    }

    /*
     * =============== 
     * G_SetSpectatorStats 
     * ===============
     */
    public static void G_SetSpectatorStats(edict_t ent) {
        gclient_t cl = ent.client;

        if (null == cl.chase_target)
            G_SetStats(ent);

        cl.ps.stats[Defines.STAT_SPECTATOR] = 1;

        // layouts are independant in spectator
        cl.ps.stats[Defines.STAT_LAYOUTS] = 0;
        if (cl.pers.health <= 0 || GameBase.level.intermissiontime != 0
                || cl.showscores)
            cl.ps.stats[Defines.STAT_LAYOUTS] |= 1;
        if (cl.showinventory && cl.pers.health > 0)
            cl.ps.stats[Defines.STAT_LAYOUTS] |= 2;

        if (cl.chase_target != null && cl.chase_target.inuse)
            //cl.ps.stats[STAT_CHASE] = (short) (CS_PLAYERSKINS +
            // (cl.chase_target - g_edicts) - 1);
            cl.ps.stats[Defines.STAT_CHASE] = (short) (Defines.CS_PLAYERSKINS
                    + cl.chase_target.index - 1);
        else
            cl.ps.stats[Defines.STAT_CHASE] = 0;
    }

    /** 
     * HelpComputer. Draws the help computer.
     */
    public static void HelpComputer(edict_t ent) {
        StringBuffer sb = new StringBuffer(256);
        String sk;
    
        if (GameBase.skill.value == 0)
            sk = "easy";
        else if (GameBase.skill.value == 1)
            sk = "medium";
        else if (GameBase.skill.value == 2)
            sk = "hard";
        else
            sk = "hard+";
    
        // send the layout
        sb.append("xv 32 yv 8 picn help "); // background
        sb.append("xv 202 yv 12 string2 \"").append(sk).append("\" "); // skill
        sb.append("xv 0 yv 24 cstring2 \"").append(GameBase.level.level_name)
                .append("\" "); // level name
        sb.append("xv 0 yv 54 cstring2 \"").append(GameBase.game.helpmessage1)
                .append("\" "); // help 1
        sb.append("xv 0 yv 110 cstring2 \"").append(GameBase.game.helpmessage2)
                .append("\" "); // help 2
        sb.append("xv 50 yv 164 string2 \" kills     goals    secrets\" ");
        sb.append("xv 50 yv 172 string2 \"");
        sb.append(Com.sprintf("%3i/%3i     %i/%i       %i/%i\" ", new Vargs(6)
                .add(GameBase.level.killed_monsters).add(
                        GameBase.level.total_monsters).add(
                        GameBase.level.found_goals).add(
                        GameBase.level.total_goals).add(
                        GameBase.level.found_secrets).add(
                        GameBase.level.total_secrets)));
    
        GameBase.gi.WriteByte(Defines.svc_layout);
        GameBase.gi.WriteString(sb.toString());
        GameBase.gi.unicast(ent, true);
    }
}