// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#pragma once

#include "../default.h"

namespace embree
{
  struct __aligned(16) GridRange
  {
    unsigned int u_start;
    unsigned int u_end;
    unsigned int v_start;
    unsigned int v_end;

    __forceinline GridRange() {}

#if defined(__MIC__)    
    __forceinline void operator=(const GridRange& v) {
      store4f((float*)this,broadcast4to16f((float*)&v));
    };
#endif

    __forceinline GridRange(unsigned int u_start, unsigned int u_end, unsigned int v_start, unsigned int v_end) 
      : u_start(u_start), u_end(u_end), v_start(v_start), v_end(v_end) {}

    __forceinline unsigned int width() const {
      return u_end-u_start+1;
    }

    __forceinline unsigned int height() const {
      return v_end-v_start+1;
    }

    __forceinline bool hasLeafSize() const
    {
#if defined(__MIC__)
      return u_end-u_start <= 1 && v_end-v_start <= 1;
#else
      const unsigned int u_size = u_end-u_start+1;
      const unsigned int v_size = v_end-v_start+1;
      assert(u_size >= 1);
      assert(v_size >= 1);
      return u_size <= 3 && v_size <= 3;
#endif
    }

    static __forceinline unsigned int split(unsigned int start,unsigned int end)
    {
      const unsigned int center = (start+end)/2;
#if defined(__MIC__)
      assert(center<end);
#else
      assert (center > start);
      assert (center < end);
#endif
      return center;
    }

    __forceinline void split(GridRange& r0, GridRange& r1) const
    {
      assert( hasLeafSize() == false );
      const unsigned int u_size = u_end-u_start+1;
      const unsigned int v_size = v_end-v_start+1;
      r0 = *this;
      r1 = *this;

      if (u_size >= v_size)
      {
        const unsigned int u_mid = split(u_start,u_end);
        r0.u_end   = u_mid;
        r1.u_start = u_mid;
      }
      else
      {
        const unsigned int v_mid = split(v_start,v_end);
        r0.v_end   = v_mid;
        r1.v_start = v_mid;
      }
    }

    __forceinline unsigned int splitIntoSubRanges(GridRange r[4]) const
    {
      assert( !hasLeafSize() );
      size_t children = 0;
      GridRange first,second;
      split(first,second);

      if (first.hasLeafSize()) {
        r[0] = first;
        children++;
      } 
      else {
        first.split(r[0],r[1]);
        children += 2;
      }

      if (second.hasLeafSize())	{
        r[children] = second;
        children++;
      }
      else {
        second.split(r[children+0],r[children+1]);
        children += 2;
      }
      return children;      
    }
  };
}
