/*
 * Renderer 5. The MIT License.
 * Copyright (c) 2022 rlkraft@pnw.edu
 * See LICENSE for details.
*/

package renderer.scene.util;

import renderer.scene.*;
import renderer.scene.primitives.*;

/**
   Several static utility methods for checking
   and/or debugging a {@link Model}.
*/
public class CheckModels
{
   /**
      Determine if there are any obvious problems with any
      {@link Model} in the {@link Scene} to be rendered.

      @param scene  the {@link Scene} to be checked
      @return true if no problem is found, false if a problem is found
   */
   public static boolean check(final Scene scene)
   {
      boolean result = true;
      for (final Position p : scene.positionList)
      {
         final boolean ok = check( p.getModel() );
         if (! ok)
         {
            result = false;
         }
      }
      return result;
   }


   /**
      Determine if there are any obvious problems with the {@link Model}
      to be rendered. The purpose of these checks is to make the renderer
      a bit more user friendly. If a user makes a simple mistake and tries
      to render a {@link Model} that is missing vertices, or primitives,
      or colors, then the user gets a helpful error message.

      @param model  the {@link Model} to be checked
      @return true if no errors are found, false if an error is found
   */
   public static boolean check(final Model model)
   {
      boolean modelError = false;
      if (model.vertexList.isEmpty() && ! model.primitiveList.isEmpty())
      {
         System.out.println(
            "**** WARNING: This model does not have any vertices.");
         modelError = true;
      }
      if (! model.vertexList.isEmpty() && model.primitiveList.isEmpty())
      {
         System.out.println(
            "**** WARNING: This model does not have any geometric primitives.");
         modelError = true;
      }
      if (! (model.vertexList.isEmpty() && model.primitiveList.isEmpty())
          && model.colorList.isEmpty())
      {
         System.out.println(
            "**** WARNING: This model does not have any colors.");
         modelError = true;
      }

      final boolean indexError = ! checkPrimitives(model);

      if (modelError || indexError)
      {
         System.out.println(model);
         System.out.flush();
      }

      return ! (modelError || indexError);
   }


   /**
      Check each {@link Primitive} in the {@link Model} to make sure that
      each index in the {@link Primitive}'s {@code vIndexList} refers to a
      valid {@link Vertex} in the {@link Model}'s {@code vertexList} and
      also that each index in the {@link Primitive}'s {@code cIndexList}
      refers to a valid {@link java.awt.Color} in the {@link Model}'s
      {@code colorList}

      @param model  the {@link Model} to be checked for consistent indexes
      @return true if no errors are found, false if an invalid index is found
   */
   public static boolean checkPrimitives(final Model model)
   {
      final int numberOfVertices = model.vertexList.size();

      boolean error = false;
      for (final Primitive p : model.primitiveList)
      {
         boolean indexError = false;
         for (final int i : p.vIndexList)
         {
            if (i >= numberOfVertices)
            {
               System.out.println(
                  "**** WARNING: This Primitive has invalid vertex index: " + i);
               indexError = true;
            }
         }
         if (indexError)
         {
            System.out.println( p );
            error = true;
         }
      }

      final int numberOfColors = model.colorList.size();

      for (final Primitive p : model.primitiveList)
      {
         boolean indexError = false;
         for (final int i : p.cIndexList)
         {
            if (i >= numberOfColors)
            {
               System.out.println(
                  "**** WARNING: This Primitive has invalid color index: " + i);
               indexError = true;
            }
         }
         if (indexError)
         {
            System.out.println( p );
            error = true;
         }
      }
      return !error;
   }



   // Private default constructor to enforce noninstantiable class.
   // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch.
   private CheckModels() {
      throw new AssertionError();
   }
}