-module(counter).

%% API functions
-export([
	start/1,
	stop/0,
	reset/1,
	get_value/0,
	incr/0,
	decr/0,
	test/0]).

-export([
	init/1,
   %~ newloop/2, %% NEW VERSION uncomment and recompile
   loop/1 %% note, loop/1 is not part of the API, 
          %% but needs to be external to enable module hot-swapping
]).

start(InitialValue) ->
	proc_lib:start(counter,init,[InitialValue]).

%%
%% Counter methods
%%
stop() ->
	?MODULE ! {exit, self()},
	receive
	{value, Value} ->
		Value
	end.

reset(ResetValue) ->
	?MODULE ! {reset, self(), ResetValue},
	receive
	{value, Value} ->
		Value
	end.

get_value() ->
	?MODULE ! {get_value, self()},
	receive
	{value, Value} ->
		Value
	end.

incr() ->
	?MODULE ! incr.

decr() ->
	?MODULE ! decr.

%%
%% Counter process loop.
%%
init(InitialValue) ->
   true = register(?MODULE,self()),
   proc_lib:init_ack({ok,InitialValue}),
	loop(InitialValue).

%%%%%% OLD VERSION starts here, comment out

loop(Value) ->
	receive
	{get_value, Pid} ->
		Pid ! {value, Value},
		counter:loop(Value);
	incr ->
		NewValue = Value + 1,
		counter:loop(NewValue);
	decr ->
		NewValue = Value - 1,
		counter:loop(NewValue);
	{reset, Pid, ResetValue} ->
		Pid ! {value, Value},
		counter:loop(ResetValue);
	{exit, Pid} ->
		Pid ! {value, Value},
		ok;
	_ ->
		counter:loop(Value)
	end.

%%%%%% OLD VERSION ends here

%%%%%% NEW VERSION starts here, uncomment

%~ loop(Value) ->
   %~ io:format("**** switching NOW! ****~n"),
   %~ counter:newloop(Value,new_parameter).

%~ newloop(Value,NewParameter) ->
   %~ receive
	%~ {get_value,Pid} ->
		%~ Pid ! {value,{Value,NewParameter}},
		%~ counter:newloop(Value,NewParameter);
	%~ incr ->
		%~ NewValue = Value + 1,
		%~ counter:newloop(NewValue,NewParameter);
	%~ decr ->
		%~ NewValue = Value - 1,
		%~ counter:newloop(NewValue,NewParameter);
	%~ {reset, Pid, ResetValue} ->
		%~ Pid ! {value, Value},
		%~ counter:newloop(ResetValue,NewParameter);
	%~ {exit, Pid} ->
		%~ Pid ! {value, Value},
		%~ ok;
	%~ _ ->
		%~ counter:newloop(Value,NewParameter)
	%~ end.

%%%%%%% NEW VERSION ends here

test() ->
	%~ io:format("start => ~w~n", [start(33)]),
	io:format("~w~n", [incr()]),
	io:format("~w~n", [decr()]),
	io:format("~w~n", [decr()]),
	io:format("~w~n", [decr()]),
	io:format("reset (previous value=~w)~n", [reset(10)]),
	io:format("get_value => ~w~n", [get_value()]),
	%~ io:format("stop => ~w~n", [stop()]),
	ok.