using System.Collections;
using System.Collections.Generic;
using Godot;
using System;

using System.Threading.Tasks;

namespace Rokojori
{
  public class MultiBakeModeCylinder:MultiBakeModeBillboardBase
  {
    public override MultiBaker.BakeMode GetBakeMode()
    {
      return MultiBaker.BakeMode.Cylinder;
    }

    public override int GetNumViews()
    {
      var cylinderViews = multiBaker.cylinderSides;

      if ( multiBaker.cylinderBottom )
      {
        cylinderViews ++;
      }

      if ( multiBaker.cylinderTop )
      {
        cylinderViews ++;
      }

      return cylinderViews;
    }

    public override void CreateBakes()
    {
      var fov = multiBaker.GetCameraFOV();
      var distance = multiBaker.GetCameraDistance();
      var outputScale = multiBaker.GetOutputScale();

      var _bakers = multiBaker.bakers;
      var mb = multiBaker;


      _bakers.ForEach(
        b =>
        {
          b.useCustomFOV = true;
          b.customFOV = fov;

          b.useCustomDistance = true;
          b.customDistance = distance;

          b.rotationMode = Baker.RotationMode.Yaw_Pitch;
        }
      );

      var index = 0;
      var mg = new MeshGeometry();  

      var numTextures = GetNumViews();
      var textureAlignment = TextureMerger.ComputeTextureAlignment( numTextures );
 

      if ( mb.cylinderTop )
      {
        _bakers[ index ].yaw = 0;
        _bakers[ index ].pitch = 90f;        

        var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );

        var q = new MeshGeometry();        
        q.AddQuad( _bakers[ index ].bakingRotation, outputScale, uv.min, uv.max );  


        if ( mb.cylinderTopOffset != 0 )
        {
          var topOffset = Vector3.Up * mb.cylinderTopOffset * outputScale * 0.5f;
          q.ApplyTranslation( topOffset, -4 );
        }

        mg.Add( q );

        if ( mb.createBackFacesForTop )
        {
          q.FlipNormalDirection();
          mg.Add( q );
        }

        index ++;
      }

      if ( mb.cylinderBottom )
      {
        _bakers[ index ].yaw = 0;
        _bakers[ index ].pitch = -90f;

        var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );

        var q = new MeshGeometry();
        q.AddQuad( _bakers[ index ].bakingRotation, outputScale, uv.min, uv.max ); 

        if ( mb.cylinderBottomOffset != 0 )
        {
          var bottomOffset = Vector3.Down * mb.cylinderBottomOffset * outputScale * 0.5f;
          q.ApplyTranslation( bottomOffset, -4 );
        }

        mg.Add( q );

        if ( mb.createBackFacesForBottom )
        {
          q.FlipNormalDirection();
          mg.Add( q );
        }

        index ++;
      }

      
      for ( int i = 0; i < mb.cylinderSides; i++ )
      {
        var angle = ( 360f * i ) / (float) mb.cylinderSides;
        _bakers[ index ].yaw = angle;
        _bakers[ index ].pitch = 0;

        var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );    
        

        var q = new MeshGeometry(); 
        q.AddQuad( _bakers[ index ].bakingRotation, outputScale, uv.min, uv.max ); 

         if ( mb.cylinderSideOffset != 0 )
        {
          var sideOffset = Vector3.Forward *_bakers[ index ].bakingRotation * mb.cylinderSideOffset * outputScale * -0.5f;
          q.ApplyTranslation( sideOffset, -4 );
        }                

        mg.Add( q );

        if ( mb.createBackFacesForSides )
        {
          q.FlipNormalDirection();
          mg.Add( q );
        }

        index++;

      }

      
      mb.X_outputMesh.Mesh = mg.GenerateMesh();  
      
    }
  }
}