/*
** Module   : CheckScreenBuffer.java
** Abstract : directive to check a screen buffer against expected contents
**
** Copyright (c) 2009-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- -----------------------Description------------------------
** 001 GES 20090126 Directive to check a screen buffer against expected
**                  contents.
** 002 IAS 20150713 Added screen template file name to check-screen-buffer failure message
** 003 TJD 20220817 When test failed log expected screen
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.goldencode.harness.test;

import com.goldencode.harness.Harness;
import com.goldencode.harness.terminal.*;

/**
 * Directive to check a screen buffer against expected contents. If a timeout
 * or interruption occurs before a screen becomes available, this directive
 * will fail.
 */
public class CheckScreenBuffer
extends ScreenPoller
{
   /** Short name for the activity. */
   private static final String NAME = "CHECK-SCREEN-BUFFER";
   
   /** Format specification for creating a description of this step. */
   private static final String SPEC = "wait = %b; millis = '%d';";
   
   /** Coordinates and contents of the region to check. */
   private ScreenRegion region = null;
   
   /** Wait until specific mode or timeout until first. */
   private boolean wait = false;
   
   /**
    * Construct an instance which waits for any screen buffer to be available.
    *
    * @param    region
    *           Coordinates and contents of the region to check.
    * @param    wait
    *           <code>true</code> to wait until the described screen becomes
    *           available OR the maximum timeout has occurred.  This means that
    *           even if a screen is already there to check, if it doesn't match
    *           this directive will wait up to a maximum of <code>millis</code>
    *           milliseconds for the matching screen to become available. In
    *           this mode, there can never be a failure before the maximum
    *           timeout occurs, since it will just continue to wait and recheck.
    *           If this is <code>false</code>, then only the first screen found
    *           will be checked and if it fails, the directive fails. The
    *           <code>millis</code> value is simply the maximum milliseconds
    *           to wait for the first screen to check. In this mode, it is
    *           important to have previously used the 
    *           <code>CLEAR-SCREEN-BUFFER</code> directive to allow a new
    *           screen to be detected.
    * @param    millis
    *           If <code>wait</code> is <code>true</code>, this is a maximum
    *           number of milliseconds to wait for the specific screen to
    *           appear. Use -1 to for an indefinite wait (no timeout) and use
    *           0 to check the current screen and immediately return. If
    *           <code>wait</code> is <code>false</code>, then this is the
    *           number of milliseconds to wait for the first screen buffer to
    *           become available and that screen will be checked. Use -1 for
    *           an indefinite wait and 0 for no wait. Notice that 0 acts the
    *           same way regardless of the <code>wait</code> flag.
    */
   public CheckScreenBuffer(ScreenRegion region, boolean wait, int millis)
   {
      super(NAME, String.format(SPEC, wait, millis), millis);
      this.region = region;
      this.wait   = wait;
   }
   
   /**
    * Core logic to check the given screen.
    *
    * @param    term
    *           The terminal that represents the system under test.
    * @param    screen
    *           The current screen on the terminal.
    *
    * @return   The reason (if there was a failure) or <code>null</code> if
    *           the screens matched.
    */
   protected String tryTest(Terminal term, char[][] screen)
   {
      return checkScreen(term, screen);
   }
   
   /**
    * Detect if the testing is complete when the first screen is tested.
    *
    * @return   <code>true</code> if the testable activity is complete when
    *           the first screen has been tested.
    */
   protected boolean firstScreenOnly()
   {
      return !wait;
   }
   
   /**
    * Core logic to compare the expected region to the actual screen.
    *
    * @param    term
    *           The terminal that represents the system under test.
    * @param    screen
    *           The current screen on the terminal.
    *
    * @return   The reason (if there was a failure) or <code>null</code> if
    *           the screens matched.
    */
   private String checkScreen(Terminal term, char[][] screen)
   {
      String reason = null;
      
      if (region != null)
      {
         int col = term.getColumns();
         int row = term.getRows();
         
         Rectangle    full   = new Rectangle(0, 0, col, row);
         ScreenRegion actual = new ScreenRegion(full, region.fname, screen, null);
         
         reason = actual.contains(region);
         if (reason != null && Harness.isDebugMode())
         {
            setExpected(region.toString());
         }
      }
      else
      {
         reason = "Missing comparison data.";
      }
      
      setLastReason(reason); 
      
      return reason;
   }
}
