//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005-2014 Simon Howard
//
// 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.
//


#include "h2def.h"
#include "p_local.h"

//==================================================================
//==================================================================
//
//                                                      CEILINGS
//
//==================================================================
//==================================================================

ceiling_t *activeceilings[MAXCEILINGS];

//==================================================================
//
//      T_MoveCeiling
//
//==================================================================
void T_MoveCeiling(thinker_t *thinker)
{
    ceiling_t *ceiling = (ceiling_t *) thinker;
    result_e res;

    switch (ceiling->direction)
    {
//              case 0:         // IN STASIS
//                      break;
        case 1:                // UP
            res = T_MovePlane(ceiling->sector, ceiling->speed,
                              ceiling->topheight, false, 1,
                              ceiling->direction);
            if (res == RES_PASTDEST)
            {
                SN_StopSequence((mobj_t *) & ceiling->sector->soundorg);
                switch (ceiling->type)
                {
                    case CLEV_CRUSHANDRAISE:
                        ceiling->direction = -1;
                        ceiling->speed = ceiling->speed * 2;
                        break;
                    default:
                        P_RemoveActiveCeiling(ceiling);
                        break;
                }
            }
            break;
        case -1:               // DOWN
            res = T_MovePlane(ceiling->sector, ceiling->speed,
                              ceiling->bottomheight, ceiling->crush, 1,
                              ceiling->direction);
            if (res == RES_PASTDEST)
            {
                SN_StopSequence((mobj_t *) & ceiling->sector->soundorg);
                switch (ceiling->type)
                {
                    case CLEV_CRUSHANDRAISE:
                    case CLEV_CRUSHRAISEANDSTAY:
                        ceiling->direction = 1;
                        ceiling->speed = ceiling->speed / 2;
                        break;
                    default:
                        P_RemoveActiveCeiling(ceiling);
                        break;
                }
            }
            else if (res == RES_CRUSHED)
            {
                switch (ceiling->type)
                {
                    case CLEV_CRUSHANDRAISE:
                    case CLEV_LOWERANDCRUSH:
                    case CLEV_CRUSHRAISEANDSTAY:
                        //ceiling->speed = ceiling->speed/4;
                        break;
                    default:
                        break;
                }
            }
            break;
    }
}

//==================================================================
//
//              EV_DoCeiling
//              Move a ceiling up/down and all around!
//
//==================================================================
int EV_DoCeiling(line_t * line, byte * arg, ceiling_e type)
{
    int secnum, rtn;
    sector_t *sec;
    ceiling_t *ceiling;

    secnum = -1;
    rtn = 0;

/* Old Ceiling stasis code
	//
	//      Reactivate in-stasis ceilings...for certain types.
	//
	switch(type)
	{
		case CLEV_CRUSHANDRAISE:
			P_ActivateInStasisCeiling(line);
		default:
			break;
	}
*/
    while ((secnum = P_FindSectorFromTag(arg[0], secnum)) >= 0)
    {
        sec = &sectors[secnum];
        if (sec->specialdata)
            continue;

        //
        // new door thinker
        //
        rtn = 1;
        ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVSPEC, 0);
        P_AddThinker(&ceiling->thinker);
        sec->specialdata = ceiling;
        ceiling->thinker.function = T_MoveCeiling;
        ceiling->sector = sec;
        ceiling->crush = 0;
        ceiling->speed = arg[1] * (FRACUNIT / 8);
        switch (type)
        {
            case CLEV_CRUSHRAISEANDSTAY:
                ceiling->crush = arg[2];        // arg[2] = crushing value
                ceiling->topheight = sec->ceilingheight;
                ceiling->bottomheight = sec->floorheight + (8 * FRACUNIT);
                ceiling->direction = -1;
                break;
            case CLEV_CRUSHANDRAISE:
                ceiling->topheight = sec->ceilingheight;
            case CLEV_LOWERANDCRUSH:
                ceiling->crush = arg[2];        // arg[2] = crushing value
            case CLEV_LOWERTOFLOOR:
                ceiling->bottomheight = sec->floorheight;
                if (type != CLEV_LOWERTOFLOOR)
                {
                    ceiling->bottomheight += 8 * FRACUNIT;
                }
                ceiling->direction = -1;
                break;
            case CLEV_RAISETOHIGHEST:
                ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
                ceiling->direction = 1;
                break;
            case CLEV_LOWERBYVALUE:
                ceiling->bottomheight =
                    sec->ceilingheight - arg[2] * FRACUNIT;
                ceiling->direction = -1;
                break;
            case CLEV_RAISEBYVALUE:
                ceiling->topheight = sec->ceilingheight + arg[2] * FRACUNIT;
                ceiling->direction = 1;
                break;
            case CLEV_MOVETOVALUETIMES8:
                {
                    int destHeight = arg[2] * FRACUNIT * 8;

                    if (arg[3])
                    {
                        destHeight = -destHeight;
                    }
                    if (sec->ceilingheight <= destHeight)
                    {
                        ceiling->direction = 1;
                        ceiling->topheight = destHeight;
                        if (sec->ceilingheight == destHeight)
                        {
                            rtn = 0;
                        }
                    }
                    else if (sec->ceilingheight > destHeight)
                    {
                        ceiling->direction = -1;
                        ceiling->bottomheight = destHeight;
                    }
                    break;
                }
            default:
                rtn = 0;
                break;
        }
        ceiling->tag = sec->tag;
        ceiling->type = type;
        P_AddActiveCeiling(ceiling);
        if (rtn)
        {
            SN_StartSequence((mobj_t *) & ceiling->sector->soundorg,
                             SEQ_PLATFORM + ceiling->sector->seqType);
        }
    }
    return rtn;
}

//==================================================================
//
//              Add an active ceiling
//
//==================================================================
void P_AddActiveCeiling(ceiling_t * c)
{
    int i;
    for (i = 0; i < MAXCEILINGS; i++)
        if (activeceilings[i] == NULL)
        {
            activeceilings[i] = c;
            return;
        }
}

//==================================================================
//
//              Remove a ceiling's thinker
//
//==================================================================
void P_RemoveActiveCeiling(ceiling_t * c)
{
    int i;

    for (i = 0; i < MAXCEILINGS; i++)
        if (activeceilings[i] == c)
        {
            activeceilings[i]->sector->specialdata = NULL;
            P_RemoveThinker(&activeceilings[i]->thinker);
            P_TagFinished(activeceilings[i]->sector->tag);
            activeceilings[i] = NULL;
            break;
        }
}

#if 0
//==================================================================
//
//              Restart a ceiling that's in-stasis
//
//==================================================================
void P_ActivateInStasisCeiling(line_t * line)
{
    int i;

    for (i = 0; i < MAXCEILINGS; i++)
        if (activeceilings[i] && (activeceilings[i]->tag == line->arg1) &&
            (activeceilings[i]->direction == 0))
        {
            activeceilings[i]->direction = activeceilings[i]->olddirection;
            activeceilings[i]->thinker.function = T_MoveCeiling;
            SN_StartSequence((mobj_t *) & activeceilings[i]->sector->soundorg,
                             SEQ_PLATFORM +
                             activeceilings[i]->sector->seqType);
        }
}
#endif

//==================================================================
//
//              EV_CeilingCrushStop
//              Stop a ceiling from crushing!
//
//==================================================================

int EV_CeilingCrushStop(line_t * line, byte * args)
{
    int i;
    int rtn;

    rtn = 0;
    for (i = 0; i < MAXCEILINGS; i++)
    {
        if (activeceilings[i] && activeceilings[i]->tag == args[0])
        {
            rtn = 1;
            SN_StopSequence((mobj_t *) & activeceilings[i]->sector->soundorg);
            activeceilings[i]->sector->specialdata = NULL;
            P_RemoveThinker(&activeceilings[i]->thinker);
            P_TagFinished(activeceilings[i]->sector->tag);
            activeceilings[i] = NULL;
            break;
        }
    }
    return rtn;
}
