--******************************************************************************************
function public.Init( pos_z )

  interface.LoadImplementation( "strategy_guide" );
  ObjSet( "int_strategy_guide", { pos_z = pos_z } );
  --ObjSet( "int_popup", { pos_z = pos_z } );
  private.last_page_type = nil;
  private.page_images_res = {};
  private.event_anim_end = {};
  private.PAGE_CHANGE_ANIM_TIME = 0.2;

  private.current_page_num = nil;
  private.toc_header = nil;
  private.toc_data = nil;
  private.pages_data = nil;

  MsgSubscribe( Command_Interface_UpdateTextures, private.WideScreenUpdate );

end;
--******************************************************************************************
function public.Destroy()

  MsgUnsubscribe( Command_Interface_UpdateTextures, private.WideScreenUpdate );

end;
--******************************************************************************************
function public.Show( page )

  ObjSet( "obj_int_strategy_guide_toc",   { alp = 0 } );
  ObjSet( "obj_int_strategy_guide_page",  { alp = 0 } );
  ObjSet( "obj_int_strategy_guide_empty", { alp = 0 } );

  ObjAttach( "int_strategy_guide", interface.originhub );

  private.last_page_type = nil;

  if private.current_page_num == nil then

    local guide_res = ObjGet( "int_strategy_guide" ).res;

    local guide = GetStrategyGuide( guide_res..".xml" );
    local chapters = guide.chapters;
    local toc = guide.toc.chapters;

    local pos = private.FindLastOf( guide_res, "/" );
    local folder = string.sub( guide_res, 1, pos - 1 );
    local image_folder = folder.."/screens/";

    private.toc_header = guide.toc.header;
    private.pages_data = {};
    private.toc_data = {};

    for i = 1, #chapters do
      local header = chapters[ i ].header;

      for j = 1, #toc do

        if ( header == toc[i] ) then
          table.insert( private.toc_data, { text = header, page = #private.pages_data + 1 } );
          break;
        end;

      end;

      local pages = chapters[ i ].pages;
      for j = 1, #pages do
        local images = pages[ j ].images;
        for k = 1, #images do 
          local pos = private.FindLastOf( images[ k ].src, ".", 1, true );
          local image_name = string.sub( images[ k ].src, 1, pos - 1 );
          images[ k ].src = image_folder..image_name;
        end;
        table.insert( private.pages_data, { text = pages[ j ].text, header = header, images = images } );
      end;

    end;
  end;

  private.current_page_num = page;
  private.ShowPage( page );

  ObjSet( "int_strategy_guide", { active = true, visible = true, input = true } );

  local event_id = "show";
  private.event_anim_end[ event_id ] = message_params;
  int_strategy_guide_impl.ShowAnim( event_id );

end;
--******************************************************************************************
function public.EventAnimEnd( event_id )

  local event_params = private.event_anim_end[ event_id ];

  ------------------------------------------------------------------------------------
  if     ( event_id == "show" ) then

  ObjSet( "int_strategy_guide_impl", { input = true } );

  ------------------------------------------------------------------------------------
  elseif ( event_id == "hide" ) then

  ObjSet( "int_strategy_guide", { active = false, visible = false, input = false } );

  ObjDetach( "int_strategy_guide" );

  ------------------------------------------------------------------------------------
  elseif ( event_id == "toc_show_first" ) then

  local prev_obj_name = "obj_int_strategy_guide_"..private.last_page_type;
  ObjSet( prev_obj_name, { active = false, visible = false } );

  private.TOCShow();

  ------------------------------------------------------------------------------------
  elseif ( event_id == "toc_show_last" ) then

  ObjSet( "obj_int_strategy_guide_toc", { input = true } );

  ------------------------------------------------------------------------------------
  elseif ( event_id == "page_show_first" ) then

  local prev_obj_name = "obj_int_strategy_guide_"..private.last_page_type;
  ObjSet( prev_obj_name, { active = false, visible = false } );

  private.ShowGuidePage( event_params );

  ------------------------------------------------------------------------------------
  elseif ( event_id == "page_show_last" ) then

  ObjSet( "obj_int_strategy_guide_page", { input = true } );

  ------------------------------------------------------------------------------------
  elseif ( event_id == "empty_show_first" ) then

  local prev_obj_name = "obj_int_strategy_guide_"..private.last_page_type;
  ObjSet( prev_obj_name, { active = false, visible = false } );

  private.EmptyShow( event_params );

  ------------------------------------------------------------------------------------
  elseif ( event_id == "empty_show_last" ) then

  ObjSet( "obj_int_strategy_guide_empty", { input = true } );

  ------------------------------------------------------------------------------------
  end;

end;
--******************************************************************************************
function public.StdPageShowAnimation( obj_name, trg_end )

  local alp = ObjGet( obj_name ).alp;
  local tme = ( 1 - alp ) * private.PAGE_CHANGE_ANIM_TIME;

  ObjAnimate( obj_name, "alp", 0, 0, trg_end,
  {
  0.0, 2, alp,
  0.2, 2, 1.0
  } );

end;
--******************************************************************************************
function public.StdPageHideAnimation( obj_name, trg_end )

  local alp = ObjGet( obj_name ).alp;
  local tme = alp * private.PAGE_CHANGE_ANIM_TIME;

  ObjAnimate( obj_name, "alp", 0, 0, trg_end,
  {
  0.0, 1, alp,
  0.2, 1, 0.0
  } );

end;
--******************************************************************************************
function public.ImageShow( res_id )

  local path = "assets/interface/impl/int_strategy_guide_impl";
  local name = "int_strategy_guide_impl";

  local trigger = function () private.SetImageRes( res_id );  end;

  local pos_fst = GetObjPosByObj( "obj_int_strategy_guide_page_image_"..res_id );

  interface.WindowShow( path, name, "wnd_int_strategy_guide_image", trigger, pos_fst, { 512, 384 } );

end;
--******************************************************************************************
function public.ImageHide()

  interface.WindowHide( "wnd_int_strategy_guide_image" );

end;
--******************************************************************************************
function public.ButtonCloseMouseDown()

  private.Hide();

end;
--******************************************************************************************
function public.ButtonTOCMouseDown()

  private.current_page_num = -1;
  private.ShowPage( private.current_page_num );

end;
--******************************************************************************************
function public.ButtonNextMouseDown()

  if ( private.current_page_num == 0 ) then

    private.current_page_num = -1;

  elseif ( private.current_page_num == -1 ) then

    private.current_page_num = 1;

  else

    private.current_page_num = private.current_page_num + 1;
    if ( private.current_page_num >= #private.pages_data ) then

      private.current_page_num = -1;

    end;

  end;
  private.ShowPage( private.current_page_num );

end;
--******************************************************************************************
function public.ButtonPrevMouseDown()

  if ( private.current_page_num == 0 ) then

    private.current_page_num = -1;

  elseif ( private.current_page_num == -1 ) then

    private.current_page_num = #private.pages_data;

  else

    private.current_page_num = private.current_page_num - 1;
    if ( private.current_page_num <= 0 ) then

      private.current_page_num = -1;

    end;

  end;
  private.ShowPage( private.current_page_num );

end;
--******************************************************************************************
function private.ButtonChapterMouseDown( chapter_page )

  private.current_page_num = chapter_page;
  private.ShowPage( private.current_page_num );

end;
--******************************************************************************************
function private.ShowToc()

  if ( private.last_page_type ) then

    local prev_obj_name = "obj_int_strategy_guide_"..private.last_page_type;
    ObjSet( prev_obj_name, { input = false } );

    local event_id = "toc_show_first";
    private.event_anim_end[ event_id ] = {};
    int_strategy_guide_impl.PageHideAnim( prev_obj_name, event_id );

  else

    private.TOCShow();

  end;

end;
--******************************************************************************************
function private.TOCShow()

  local next_obj_name = "obj_int_strategy_guide_toc";

  ObjSet( next_obj_name, { active = true, visible = true } );

  private.last_page_type = "toc";

  local title = private.toc_header;
  local toc   = private.toc_data;

  private.SetTitleAndCount( title, - 1 );

  for i = 1, #toc, 1 do

    local chapter = toc[ i ];

    local obj_name = "obj_int_strategy_guide_toc_chapter_"..i;
    local txt_name = "txt_int_strategy_guide_toc_chapter_"..i;

    local is_obj = ObjGet( obj_name ).visible;

    if ( is_obj ) then

      ObjSet( txt_name, { text = chapter.text } );

      local txt_data = ObjGet( txt_name );

      ObjSet( obj_name,
      {
      event_mdown    = function () private.ButtonChapterMouseDown( chapter.page ); end,
      inputrect_init = 1,
      inputrect_x    = - ( 0.5 * txt_data.draw_width  ),
      inputrect_y    = - ( 0.5 * txt_data.draw_height ),
      inputrect_w    =           txt_data.draw_width,
      inputrect_h    =           txt_data.draw_height
      } );

    else
      
      DbgTrace( string.format( "[ interface.ERROR ][ int_strategy_guide ] Object < %s > missing!", obj_name ) );

    end;

  end;

  local next_event_id = "toc_show_last";
  private.event_anim_end[ next_event_id ] = {};
  int_strategy_guide_impl.PageShowAnim( next_obj_name, next_event_id );

end;
--******************************************************************************************
function private.ShowPage( page_index )

  if ( page_index == -1 ) then

    private.ShowToc();

  else

    local page_type = "page";
    local page_func = private.ShowGuidePage;
    local show = false;

    if ( page_index == 0 ) then

      --DbgTrace( "EMPTY" );

      page_type = "empty";
      page_func = private.EmptyShow;
      show = true;

    elseif ( page_index <= #private.pages_data ) then

      show = true;

    end;

    if ( show ) then

      if ( private.last_page_type ) then

        local prev_obj_name = "obj_int_strategy_guide_"..private.last_page_type;
        ObjSet( prev_obj_name, { input = false } );

        local event_id = page_type.."_show_first";
        private.event_anim_end[ event_id ] = { page = page_index };
        int_strategy_guide_impl.PageHideAnim( prev_obj_name, event_id );

      else

        page_func( { page = page_index } );

      end;

    end;

  end;

end;
--******************************************************************************************
function private.ShowGuidePage( params )

  local next_obj_name = "obj_int_strategy_guide_page";

  ObjSet( next_obj_name, { active = true, visible = true } );

  private.last_page_type = "page";

  local page   = params[ "page"   ];
  local title  = private.pages_data[ page ].header;
  local images = private.pages_data[ page ].images;
  local text   = private.pages_data[ page ].text;

  private.SetTitleAndCount( title, page );

  local text_name = "txt_int_strategy_guide_page";

  local text_data = int_strategy_guide_impl.PAGE_CONTENT_DATA[ #images ][ "text" ];

  local text_out = "- "..string.gsub( text, "&nl&", "\n- " );

  text_data[ "text" ] = text_out;

  ObjSet( text_name, text_data );

  local text_height = ObjGet( text_name ).draw_height;

  ObjSet( text_name, { drawoff_y = ( 0.5 * text_height ) } );

  for i = 1, 6, 1 do

  local image_obj = "obj_int_strategy_guide_page_image_"..i;
  local image_spr = "spr_int_strategy_guide_page_image_"..i;

  if ( images[ i ] ) then

    local image_res = images[ i ].src;

    private.page_images_res[ i ] = image_res;

    local image_obj_data = int_strategy_guide_impl.PAGE_CONTENT_DATA[ #images ][ "images" ][ i ];

    image_obj_data[ "active"  ] = true;
    image_obj_data[ "visible" ] = true;
    image_obj_data[ "input"   ] = true;

    ObjSet( image_obj, image_obj_data );
    ObjSet( image_spr, { res = image_res } );

  else

    ObjSet( image_obj, { active = false, visible = false, input = false } );

  end;

  end;

  local next_event_id = "page_show_last";
  private.event_anim_end[ next_event_id ] = {};
  int_strategy_guide_impl.PageShowAnim( next_obj_name, next_event_id );

end;
--******************************************************************************************
function private.EmptyShow( params )

  local next_obj_name = "obj_int_strategy_guide_empty";

  ObjSet( next_obj_name, { active = true, visible = true } );

  local page = params[ "page" ];

  private.last_page_type = "empty";

  private.SetTitleAndCount( "", page );

  local next_event_id = "empty_show_last";
  private.event_anim_end[ next_event_id ] = {};
  int_strategy_guide_impl.PageShowAnim( next_obj_name, next_event_id );

end;
--******************************************************************************************
function private.SetTitleAndCount( title, page )

  ng_global.strategy_guide_page = page;

  ObjSet( "txt_int_strategy_guide_title", { text = title } );

  page = page + 1;

  if ( page <= 0 ) then

    ng_global.strategy_guide_page = - 1;

    page = "";

  end;

  ObjSet( "txt_int_strategy_guide_count", { text = page } );

end;
--******************************************************************************************
function private.SetImageRes( res_id )

  ObjSet( "spr_int_strategy_guide_image", { res = private.page_images_res[ res_id ] } );

end;
--******************************************************************************************
function private.Hide()

  ObjSet( "int_strategy_guide_impl", { input = false } );

  local event_id = "hide";
  private.event_anim_end[ event_id ] = message_params;
  int_strategy_guide_impl.HideAnim( event_id );

end;
--******************************************************************************************
function private.WideScreenUpdate()

  interface.WideScreenUpdate( "strategy_guide" );

end;
--******************************************************************************************
-- получение позиции символа в строке при поиске с конца
--******************************************************************************************
function private.FindLastOf( str, smb, init, plain )

  local substr = str;
  local result = 0;
  local pos = -1;
  while ( string.find( substr, smb, init, plain ) ~= nil ) do
    pos = string.find( substr, smb, init, plain );
    substr = string.sub( substr, pos + 1, string.len( substr ) );
    result = result + pos;
  end;
  return result;
  
end;

--******************************************************************************************