%% @author Marc Worrell <marc@worrell.nl>
%% @copyright 2009 Marc Worrell

%% @doc Start/stop functions for Zotonic

%% Copyright 2009 Marc Worrell
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%% 
%%     http://www.apache.org/licenses/LICENSE-2.0
%% 
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.

-module(zotonic).
-author('Marc Worrell <marc@worrell.nl>').

-export([start/0, start/1, stop/0, stop/1, ping/0, status/0, status/1, update/0, update/1, run_tests/0, ensure_started/1]).

-compile([{parse_transform, lager_transform}]).

-define(MIN_OTP_VERSION, "R14B03").


ensure_started(App) ->
    case application:start(App) of
        ok ->
            ok;
        {error, {not_started, Dep}} ->
            case ensure_started(Dep) of
                ok ->
                    ensure_started(App);
                Error ->
                    Error
            end;
        {error, {already_started, App}} ->
            ok;
        {error, Reason} ->
            Reason
    end.

%% @spec start() -> ok
%% @doc Start the zotonic server.
start() -> start([]).
	
%% @spec start(_Args) -> ok
%% @doc Start the zotonic server.
start(_Args) ->
    test_erlang_version(),
    zotonic_deps:ensure(),    
    case ensure_started(zotonic) of
        ok -> ok;
        Error ->
            Message = if is_tuple(Error) -> 
                              string:join([z_convert:to_list(E) || E <- tuple_to_list(Error)], ": ");
                         is_list(Error) -> 
                              Error;
                         true -> 
                              z_convert:to_list(Error)
                      end,
            lager:error("Zotonic failed to start application: ~s~n", [Message]),
            init:stop()
    end.

%% @spec stop() -> ok
%% @doc Stop the zotonic server.
stop() ->
    Res = application:stop(zotonic),
    application:stop(eiconv),
    application:stop(mnesia),
    application:stop(lager),
    application:stop(webzmachine),
    application:stop(crypto),
    Res.


%% @spec stop([Node]) -> void()
%% @doc Stop a zotonic server on a specific node
stop([Node]) ->
    io:format("Stopping:~p~n",[Node]),
    case net_adm:ping(Node) of
    	pong -> rpc:cast(Node, init, stop, []);
    	pang -> io:format("There is no node with this name~n")
    end,
    init:stop().

%% @doc Just returns 'pong'; used by shell scripts to determine if node is alive.
ping() ->
    pong.

%% @spec status() -> ok
%% @doc Print the status of the current node.
status() ->
    status([node()]).

%% @spec status([node()]) -> ok
%% @doc Get server status.  Prints the state of sites running.
status([Node]) ->
	[io:format("~-20s- ~s~n", [Site, Status]) || [Site,Status|_] <- rpc:call(Node, z_sites_manager, get_sites_status, [])],
	ok.

%% @spec update() -> ok
%% @doc Update the server.  Compiles and loads any new code, flushes caches and rescans all modules.
update() ->
    z:m(),
    ok.


%% @spec update([Node]) -> ok
%% @doc Update the server on a specific node with new code on disk and flush the caches.
update([Node]) ->
    io:format("Update:~p~n",[Node]),
    case net_adm:ping(Node) of
    	pong -> rpc:cast(Node, zotonic, update, []);
    	pang -> io:format("There is no node with this name~n")
    end,
    init:stop().


test_erlang_version() ->
    Version = erlang:system_info(otp_release),
    if
        Version < ?MIN_OTP_VERSION ->
            lager:error("Zotonic needs at least Erlang release ~p; this is ~p", [?MIN_OTP_VERSION, Version]),
            erlang:exit({minimal_otp_version, ?MIN_OTP_VERSION});
        true ->
            ok
    end.

run_tests() ->
    z_media_preview_tests:test().