/* Copyright (c) 2000 Shlomi Fish
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
/*
 * move.c - move and move stacks routines for Freecell Solver
 *
 */

#define BUILDING_DLL 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "move.h"
#include "state.h"
#include "fcs_enums.h"

#include "inline.h"
#include "unused.h"

#ifdef FCS_USE_COMPACT_MOVE_TOKENS
const fcs_internal_move_t fc_solve_empty_move = {0,0,0,0};
#else
const fcs_internal_move_t fc_solve_empty_move = {"\0\0\0\0"};
#endif

/*
 * This function performs a given move on a state
 */
void fc_solve_apply_move(
    fcs_state_t * const ptr_state_key,
    fcs_state_locs_struct_t * const locs,
    const fcs_internal_move_t move
    FREECELLS_AND_STACKS_ARGS()
)
{
    fcs_card_t card;
    fcs_cards_column_t col;

#define state_key (ptr_state_key)
    switch (fcs_int_move_get_type(move))
    {
        case FCS_MOVE_TYPE_STACK_TO_STACK:
        {
            fcs_col_transfer_cards(fcs_state_get_col(*state_key, fcs_int_move_get_dest_stack(move)), fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move)), fcs_int_move_get_num_cards_in_seq(move));
        }
        break;
        case FCS_MOVE_TYPE_FREECELL_TO_STACK:
        {
            col = fcs_state_get_col(*state_key, fcs_int_move_get_dest_stack(move));
            fcs_col_push_card(col, fcs_freecell_card(*state_key, fcs_int_move_get_src_freecell(move)));
            fcs_empty_freecell(*state_key, fcs_int_move_get_src_freecell(move));
        }
        break;
        case FCS_MOVE_TYPE_FREECELL_TO_FREECELL:
        {
            card = fcs_freecell_card(*state_key, fcs_int_move_get_src_freecell(move));
            fcs_put_card_in_freecell(*state_key, fcs_int_move_get_dest_freecell(move), card);
            fcs_empty_freecell(*state_key, fcs_int_move_get_src_freecell(move));
        }
        break;

        case FCS_MOVE_TYPE_STACK_TO_FREECELL:
        {
            col = fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move));
            fcs_col_pop_card(col, card);
            fcs_put_card_in_freecell(*state_key, fcs_int_move_get_dest_freecell(move), card);
        }
        break;

        case FCS_MOVE_TYPE_STACK_TO_FOUNDATION:
        {
            col = fcs_state_get_col(
                *state_key,
                fcs_int_move_get_src_stack(move)
                );
            fcs_col_pop_top(col);
            fcs_increment_foundation(*state_key, fcs_int_move_get_foundation(move));
        }
        break;

        case FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION:
        {
            fcs_empty_freecell(*state_key, fcs_int_move_get_src_freecell(move));
            fcs_increment_foundation(*state_key, fcs_int_move_get_foundation(move));
        }
        break;

#ifndef FCS_FREECELL_ONLY
        case FCS_MOVE_TYPE_SEQ_TO_FOUNDATION:
        {
            col = fcs_state_get_col(*state_key, fcs_int_move_get_src_stack(move));
            for (int i=0 ; i<13 ; i++)
            {
                fcs_col_pop_top(col);
                fcs_increment_foundation(*state_key, fcs_int_move_get_foundation(move));
            }
        }
        break;
#endif

        case FCS_MOVE_TYPE_CANONIZE:
        {
            if (locs)
            {
                fc_solve_canonize_state_with_locs(
                    state_key,
                    locs
                    PASS_FREECELLS(freecells_num)
                    PASS_STACKS(stacks_num)
                );
            }
            else
            {
                fc_solve_canonize_state (state_key
                    PASS_FREECELLS(freecells_num)
                    PASS_STACKS(stacks_num)
                );
            }
        }
        break;

    }
#undef state_key
}


#define DERIVED_STATES_LIST_GROW_BY 16
void fc_solve_derived_states_list_add_state(
        fcs_derived_states_list_t * list,
        fcs_collectible_state_t * state,
        int context
        )
{
    if (
        (!(
           (list->num_states+(list->states != NULL))
           & (DERIVED_STATES_LIST_GROW_BY-1)
          )
        )
       )
    {
        (list)->states = SREALLOC(
            (list)->states,
            list->num_states
            + (list->states!=NULL)
            + DERIVED_STATES_LIST_GROW_BY
        );
    }
    (list)->states[(list)->num_states].state_ptr = state;
    (list)->states[(list)->num_states++].context.i = context;
}

