#!/usr/bin/env escript
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil; fill-column: 92-*-
%% ex: ts=4 sw=4 et

%% Copyright: Copyright (c) 2012 Opscode, Inc.
%% License: Apache License, Version 2.0
%%
%% 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.

%% TODO: The cookie used by erchef should be part of config
-define(SELF, 'reindexer@127.0.0.1').
-define(ERCHEF, 'erchef@127.0.0.1').
-define(ERCHEF_COOKIE, 'erchef').

-define(OSC_ORG_ID, <<"00000000000000000000000000000000">>).
-define(OSC_ORG_NAME, 'open-source-chef').

%% @doc Perform server-side reindexing of an Open Source Chef Server.  Pre-Chef 11 servers
%% provided a REST API endpoint to perform reindexing via knife, but this is more properly
%% thought of as an administrative task, rather than a "user" task.
%%
%% Currently, three command arguments are accepted:
%%
%%     drop: Removes all entries from the index.  Information in the database is untouched.
%%     reindex: Sends information stored in the database to the index again.
%%     complete: same as "drop" followed by "reindex"
%%
%% In most cases, 'complete' is desired, but the option to perform the individual steps is
%% made avilable for POWER USERS!
%%
%% Supplying either no argument or a wrong argument are errors.
main(Args) ->
    init_network(),
    Context = make_context(),
    Command = validate_args(Args),
    perform(Command, Context, {?OSC_ORG_ID, ?OSC_ORG_NAME}).

validate_args([]) ->
    io:format("You didn't specify a command!  Use either 'drop', 'reindex', or 'complete'"),
    halt(1);
validate_args([Command]) when Command =:= "reindex";
                              Command =:= "drop";
                              Command =:= "complete" ->
    list_to_atom(Command);
validate_args([Command]) ->
    io:format("Unrecognized command ~p~n", [Command]),
    halt(1).

%% @doc Actually do the reindexing.
-spec perform(drop | complete | reindex,
              Context :: term(),
              {OrgId::binary(), OrgName::binary()}) -> term().
perform(drop, _Context, {OrgId, _OrgName}) ->
    io:format("Removing all index entries~n"),
    ok = rpc:call(?ERCHEF, chef_solr, delete_search_db, [OrgId]);
perform(reindex, Context, OrgInfo) ->
    io:format("Sending all data to be indexed again.  It may take some time before everything is available via search.~n"),
    ok = rpc:call(?ERCHEF, chef_reindex, reindex, [Context, OrgInfo]);
perform(complete, Context, OrgInfo) ->
    %% Just do everything
    perform(drop, Context, OrgInfo),
    perform(reindex, Context, OrgInfo).

make_context() ->
    ReqId = base64:encode(crypto:md5(term_to_binary(make_ref()))),
    rpc:call(?ERCHEF, chef_db, make_context, [ReqId]).

init_network() ->
    net_kernel:start([?SELF, longnames]),
    erlang:set_cookie(node(), ?ERCHEF_COOKIE),
    pong = net_adm:ping(?ERCHEF).
