using AGXUnity;
using AGXUnity.Utils;
using UnityEngine;

public class WaterHeightField : ScriptComponent
{
  public int m_resolutionX = 256;
  public int m_resolutionY = 256;

  public bool m_debug;

  float m_physicalSizeX = 5;
  float m_physicalSizeY = 5;

  public OceanGeometry oceanGeometry;

  agx.RealVector m_heights;
  agxCollide.HeightField m_heightField;
  agxCollide.Geometry m_heightFieldGeometry;

  public WavesGenerator m_wavesGenerator;
  double[] m_csharpHeights;

  bool m_initialized = false;
  protected override bool Initialize()
  {
    m_wavesGenerator = GetComponent<WavesGenerator>();
    oceanGeometry = GetComponent<OceanGeometry>();
    m_physicalSizeX = m_physicalSizeY = oceanGeometry.getLengthScale() * 2;
    return base.Initialize();
  }

  void InitializeHeightField()
  {
    if ( m_initialized )
      return;

    int capacity = (int)((m_resolutionX) * (m_resolutionY));
    m_heights = new agx.RealVector( capacity );
    for ( var i = 0; i < m_resolutionX; i++ )
      for ( var j = 0; j < m_resolutionY; j++ )
        m_heights.Add( 0 );

    if ( m_heightFieldGeometry != null )
      GetSimulation().remove( m_heightFieldGeometry );

    m_csharpHeights = new double[ ( m_resolutionX ) * ( m_resolutionY ) ];

    m_heightField = new agxCollide.HeightField( (uint)m_resolutionX,
                                     (uint)m_resolutionY,
                                     m_physicalSizeX,
                                     m_physicalSizeY,
                                     m_heights,
                                     false,
                                     150.0 );
    m_heightFieldGeometry = new agxCollide.Geometry( m_heightField );

    var inst = WindAndWaterManager.Instance.GetInitialized<WindAndWaterManager>();
    var nat = inst.Native;
    nat.addWater( m_heightFieldGeometry );

    var transform = agx.AffineMatrix4x4.rotate(agx.Vec3.Z_AXIS(),
                                           agx.Vec3.Y_AXIS()) * new agx.AffineMatrix4x4(new agx.EulerAngles(0, Mathf.PI, 0)) *
               agx.AffineMatrix4x4.translate(new Vector3(0,
                                                          0,
                                                          0).ToHandedVec3());
    m_heightFieldGeometry.setLocalTransform( transform );
    GetSimulation().add( m_heightFieldGeometry ); //agxSDK.Simulation
    m_initialized = true;
  }


  // Update is called once per frame
  void Update()
  {
    float thisLengthScale = oceanGeometry.getLengthScale() * 2;

    if ( !m_initialized || m_resolutionX * m_resolutionY != m_csharpHeights.Length || thisLengthScale != m_physicalSizeX ) {
      m_physicalSizeX = m_physicalSizeY = thisLengthScale;
      InitializeHeightField();
    }

    float WaveHeight = 1.0f;

    for ( int i = 0; i < m_resolutionX; i++ ) {
      float xpos = ((m_physicalSizeX / m_resolutionX) * i) - m_physicalSizeX / 2;
      for ( int j = 0; j < m_resolutionY; j++ ) {
        float zpos = ((m_physicalSizeY / m_resolutionY) * j) - m_physicalSizeY / 2;
        int idx = j * m_resolutionX + i;
        Vector3 position = new Vector3(xpos, 0, zpos);
        Vector3 pos = WaveHeight * m_wavesGenerator.GetWaterDisplacement(position);

        m_csharpHeights[ idx ] = pos.y;
      }
    }

    m_heights.Set( m_csharpHeights );
    m_heightField.setHeights( m_heights );
  }

  void OnDrawGizmos()
  {
    if ( m_debug == false )
      return;

    float scaleX = m_physicalSizeX / m_resolutionX;
    float scaleY = m_physicalSizeY / m_resolutionY;
    if ( Application.isPlaying ) {
      if ( m_heights != null ) {
        for ( int x = 0; x <= m_resolutionX; x++ ) {
          float X = ((float)x - (float)m_resolutionX / 2.0f) * scaleX;
          for ( int y = 0; y <= m_resolutionY; y++ ) {
            float Y = ((float)y - (float)m_resolutionY / 2.0f) * scaleY;
            Vector3 position = new Vector3(X, 0, Y);
            Vector3 pos = m_wavesGenerator.GetWaterDisplacement(position);
            Gizmos.color = Color.red;
            Gizmos.DrawCube( pos + position, new Vector3( 0.1f, 0.1f, 0.1f ) );
          }
        }
      }
    }
  }
}
