pColorPacket CAtmoColorCalculator::AnalyzeHSV(tHSVColor *HSV_Img)
{
  int i; // counter

  int AtmoSetup_EdgeWeighting  = m_pAtmoConfig->getLiveView_EdgeWeighting();
  int AtmoSetup_WidescreenMode = m_pAtmoConfig->getLiveView_WidescreenMode();
  int AtmoSetup_DarknessLimit  = m_pAtmoConfig->getLiveView_DarknessLimit();
  int AtmoSetup_BrightCorrect  = m_pAtmoConfig->getLiveView_BrightCorrect();
  int AtmoSetup_SatWinSize     = m_pAtmoConfig->getLiveView_SatWinSize();
  int AtmoSetup_NumZones       = m_pAtmoConfig->getZoneCount();
  tHSVColor *temp_Img;

  if(AtmoSetup_NumZones != m_LastNumZones)
  {
     delete[] m_Weight;
     delete[] m_hue_hist;
     delete[] m_windowed_hue_hist;
     delete[] m_most_used_hue_last;
     delete[] m_most_used_hue;
     delete[] m_sat_hist;
     delete[] m_windowed_sat_hist;
     delete[] m_most_used_sat;
     delete[] m_Zone_Weights;
     delete[] m_average_v;
     delete[] m_average_counter;

     m_Weight              = new int[AtmoSetup_NumZones * IMAGE_SIZE];
     m_Zone_Weights        = new int*[AtmoSetup_NumZones];
     for(int i = 0; i < AtmoSetup_NumZones; i++)
         m_Zone_Weights[i] = &m_Weight[i * IMAGE_SIZE];

     m_hue_hist            = new long int[(h_MAX+1) * AtmoSetup_NumZones];
     m_windowed_hue_hist   = new long int[(h_MAX+1) * AtmoSetup_NumZones];

     m_most_used_hue_last  = new int[AtmoSetup_NumZones];
     m_most_used_hue       = new int[AtmoSetup_NumZones];
     memset( m_most_used_hue_last, 0, sizeof(int) * AtmoSetup_NumZones);

     m_sat_hist           = new long int[(s_MAX+1) * AtmoSetup_NumZones];
     m_windowed_sat_hist  = new long int[(s_MAX+1) * AtmoSetup_NumZones];
     m_most_used_sat      = new int[AtmoSetup_NumZones];

     m_average_v         = new long int[AtmoSetup_NumZones];
     m_average_counter   = new int[AtmoSetup_NumZones];

     m_LastNumZones = AtmoSetup_NumZones;
  }


  // calculate only if setup has changed
  if ((AtmoSetup_EdgeWeighting != m_LastEdgeWeighting) ||
      (AtmoSetup_WidescreenMode != m_LastWidescreenMode) ||
      (m_pAtmoConfig->getZonesTopCount() != m_LastLayout_TopCount) ||
      (m_pAtmoConfig->getZonesBottomCount() != m_LastLayout_BottomCount) ||
      (m_pAtmoConfig->getZonesLRCount() !=  m_LastLayout_LRCount) ||
      (m_pAtmoConfig->m_UpdateEdgeWeightningFlag != 0)
     )
  {

      for(i = 0 ;i < AtmoSetup_NumZones; i++) {
          CAtmoZoneDefinition *pZoneDef = m_pAtmoConfig->getZoneDefinition(i);
          if(pZoneDef)
          {
             pZoneDef->UpdateWeighting(m_Zone_Weights[i],
                                                              AtmoSetup_WidescreenMode,
                                                              AtmoSetup_EdgeWeighting);
#ifdef _debug_zone_weight_
             char filename[128];
             sprintf(filename, "zone_%d_gradient_debug.bmp",i);
             pZoneDef->SaveZoneBitmap( filename );
             sprintf(filename, "zone_%d_weight_%d_debug.bmp",i,AtmoSetup_EdgeWeighting);
             pZoneDef->SaveWeightBitmap(filename, m_Zone_Weights[i] );
#endif
          }

     }
     m_pAtmoConfig->m_UpdateEdgeWeightningFlag = 0;

     m_LastEdgeWeighting      = AtmoSetup_EdgeWeighting;
     m_LastWidescreenMode     = AtmoSetup_WidescreenMode;
     m_LastLayout_TopCount    = m_pAtmoConfig->getZonesTopCount();
     m_LastLayout_BottomCount = m_pAtmoConfig->getZonesBottomCount();
     m_LastLayout_LRCount     = m_pAtmoConfig->getZonesLRCount();
  }

  AtmoSetup_DarknessLimit = AtmoSetup_DarknessLimit * 10;


  /***************************************************************************/
  /* Hue                                                                     */
  /***************************************************************************/
  /*----------------------------*/
  /* hue histogram builtup      */
  /*----------------------------*/
  // HSV histogram
  // long int hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1];

  // average brightness (value)
  // m_average_v m_average_counter

  // clean histogram --> calloc
  memset(m_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
  memset(m_average_v, 0, sizeof(long int) * AtmoSetup_NumZones);
  memset(m_average_counter, 0, sizeof(int) * AtmoSetup_NumZones);

  temp_Img = HSV_Img;
  i = 0;
  for (int row = 0; row < CAP_HEIGHT; row++)
  {
    for (int column = 0; column < CAP_WIDTH; column++)
    {
      // forget black bars: perform calculations only if pixel has some luminosity
	  if ((*temp_Img).v > AtmoSetup_DarknessLimit)
      {
        // builtup histogram for the x Zones of the Display
        for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
        {
          // Add weight to channel
         // Weight(zone, pixel_nummer) m_Weight[((zone) * (IMAGE_SIZE)) + (pixel_nummer)]
         // m_hue_hist[zone*(h_MAX+1) + HSV_Img[i].h] += m_Zone_Weights[zone][i] * HSV_Img[i].v;
            m_hue_hist[zone*(h_MAX+1) + (*temp_Img).h] += m_Zone_Weights[zone][i] * temp_Img->v;

            if(m_Zone_Weights[zone][i] > 0) {
               m_average_v[zone] += temp_Img->v;
               m_average_counter[zone]++;
            }

        }
        // calculate brightness average
      }
      temp_Img++;
      i++;
    }
  }

  /*----------------------------*/
  /* hue histogram windowing    */
  /*----------------------------*/
  // windowed HSV histogram
  // long int w_hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1]; -> m_windowed_hue_hist
  // clean windowed histogram
  memset(m_windowed_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
  // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
  int hue_windowsize = m_pAtmoConfig->getLiveView_HueWinSize();

  for (i = 0; i < h_MAX+1; i++) // walk through histogram [0;h_MAX]
  {
    // windowing from -hue_windowsize -> +hue_windowsize
    for (int mywin = -hue_windowsize; mywin < hue_windowsize+1; mywin++)
    {
      // addressed histogram candlestick
      int myidx = i + mywin;

      // handle beginning of windowing -> roll back
      if (myidx < 0)     { myidx = myidx + h_MAX + 1; }

      // handle end of windowing -> roll forward
      if (myidx > h_MAX) { myidx = myidx - h_MAX - 1; }

      // Apply windowing to all x zones
      for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
      {
        // apply lite triangular window design with gradient of 10% per discrete step
        m_windowed_hue_hist[(zone * (h_MAX+1)) + i] += m_hue_hist[(zone * (h_MAX+1)) + myidx] * ((hue_windowsize+1)-abs(mywin)); // apply window
      }
    }
  }

  /*--------------------------------------*/
  /* analyze histogram for most used hue  */
  /*--------------------------------------*/
  // index of last maximum
  // static int most_used_hue_last[CAP_MAX_NUM_ZONES] = {0, 0, 0, 0, 0}; --> m_most_used_hue_last

  // resulting hue for each channel
  //int most_used_hue[CAP_MAX_NUM_ZONES]; --> m_most_used_hue

  FindMostUsed(AtmoSetup_NumZones, m_most_used_hue, m_windowed_hue_hist);
  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue[zone]];
    if (percent > 0.93f) // less than 7% difference?
        m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
     else
        m_most_used_hue_last[zone] = m_most_used_hue[zone];
  }

  /*
  memset(m_most_used_hue, 0, sizeof(int) * AtmoSetup_NumZones);

  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    long int value = 0;
    for (i = 0; i < h_MAX+1; i++) // walk through histogram
    {
      long int tmp = m_windowed_hue_hist[ (zone * (h_MAX+1)) + i ];
      if (tmp > value) // if new value bigger then old one
      {
        m_most_used_hue[zone] = i;     // remember index
        value = tmp; // w_hue_hist[zone][i]; // and value
      }
    }

    float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)value;
    if (percent > 0.93f) // less than 7% difference?
    {
      m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
    }

    m_most_used_hue_last[zone] = m_most_used_hue[zone]; // save current index of most used hue
  }
  */

  /***************************************************************************/
  /* saturation                                                              */
  /***************************************************************************/
  // sat histogram
  // long int sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1];  -> m_sat_hist
  // hue of the pixel we are working at
  int pixel_hue = 0;
  // clean histogram
  memset(m_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);

  /*--------------------------------------*/
  /* saturation histogram builtup         */
  /*--------------------------------------*/
  i = 0;
  temp_Img = HSV_Img;
  for (int row = 0; row < CAP_HEIGHT; row++)
  {
    for (int column = 0; column < CAP_WIDTH; column++)
    {
      // forget black bars: perform calculations only if pixel has some luminosity
	  if ((*temp_Img).v > AtmoSetup_DarknessLimit)
      {
        // find histogram position for pixel
        pixel_hue = (*temp_Img).h;

        // TODO:   brightness calculation(if we require it some time)

        for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
        {
          // only use pixel for histogram if hue is near most_used_hue
          if ((pixel_hue > m_most_used_hue[zone] - hue_windowsize) &&
              (pixel_hue < m_most_used_hue[zone] + hue_windowsize))
          {
            // build histogram
            // sat_hist[channel][HSV_Img[i].s] += Weight[i].channel[channel] * HSV_Img[i].v;
            m_sat_hist[zone * (s_MAX+1) + (*temp_Img).s ] += m_Zone_Weights[zone][i] * (*temp_Img).v;

          }
        }
      }
      i++;
      temp_Img++;
    }
  }

  /*--------------------------------------*/
  /* saturation histogram windowing       */
  /*--------------------------------------*/
   // windowed HSV histogram
   // long int w_sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; --> m_windowed_sat_hist
   // clean windowed histogram
   memset(m_windowed_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
   // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
   int sat_windowsize = AtmoSetup_SatWinSize;

   // walk through histogram [0;h_MAX]
   for (i = 0; i < s_MAX + 1; i++)
   {
     // windowing from -hue_windowsize -> +hue_windowsize
     for (int mywin = -sat_windowsize; mywin < sat_windowsize+1; mywin++)
     {
       // addressed histogram candlestick
       int myidx = i + mywin;

       // handle beginning of windowing -> roll back
       if (myidx < 0)     { myidx = myidx + s_MAX + 1; }

       // handle end of windowing -> roll forward
       if (myidx > h_MAX) { myidx = myidx - s_MAX - 1; }

       for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
       {
         /*
            apply lite triangular window design with
            gradient of 10% per discrete step
         */
         /*
         w_sat_hist[channel][i] += sat_hist[channel][myidx] *
                                  ((sat_windowsize+1)-abs(mywin)); // apply window
         */
         m_windowed_sat_hist[zone * (s_MAX+1) + i] += m_sat_hist[zone* (h_MAX+1) + myidx] *
                                  ((sat_windowsize+1)-abs(mywin)); // apply window
       }
     }
   }

  /*--------------------------------------*/
  /* analyze histogram for most used sat  */
  /*--------------------------------------*/
   // resulting sat (most_used_hue) for each channel
  // int most_used_sat[CAP_MAX_NUM_ZONES];->m_most_used_sat

  FindMostUsed(AtmoSetup_NumZones, m_most_used_sat, m_windowed_sat_hist);
  /*
  memset(m_most_used_sat, 0, sizeof(int) * AtmoSetup_NumZones);

  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    int value = 0;
    // walk trough histogram
    for (i = 0; i < s_MAX+1; i++)
    {
      // if new value bigger then old one
      int tmp = m_windowed_sat_hist[zone * (s_MAX+1) + i];
      // if (w_sat_hist[channel][i] > value)
      if (tmp > value)
      {
        // remember index
        m_most_used_sat[zone] = i;
        // and value
        value = tmp;
      }
    }
  }
  */


  /*----------------------------------------------------------*/
  /* calculate average brightness within HSV image            */
  /* uniform Brightness for all channels is calculated        */
  /*----------------------------------------------------------*/
  /* code integrated into "hue histogram builtup" to save some looping time!
  int l_counter = 0;
  // average brightness (value)
  long int value_avg = 0;
  i = 0;
  for (int row = 0; row < CAP_HEIGHT; row++)
  {
    for (int column = 0; column < CAP_WIDTH; column++)
    {
      // find average value: only use bright pixels for luminance average
	  if (HSV_Img[i].v > AtmoSetup_DarknessLimit)
      {
        // build brightness average
        value_avg += HSV_Img[i].v;
        l_counter++;
      }
      i++;
    }
  }
  // calculate brightness average
  if (l_counter > 0) { value_avg = value_avg / l_counter; }
    else { value_avg = AtmoSetup_DarknessLimit; }

  */


  /*----------------------------*/
  /* adjust and copy results    */
  /*----------------------------*/
  tHSVColor hsv_pixel;
  // storage container for resulting RGB values
  pColorPacket output_colors;
  AllocColorPacket(output_colors, AtmoSetup_NumZones);

  // adjust brightness
//  int new_value = (int) ((float)value_avg * ((float)AtmoSetup_BrightCorrect / 100.0));
//  if (new_value > 255) new_value = 255;  // ensure brightness isn't set too high
//  hsv_pixel.v = (unsigned char)new_value;

  /*
  // calculate brightness average
  for(int zone = 0; zone < AtmoSetup_NumZones; zone++) {
      if(m_average_counter[zone] > 0)
          m_average_v[zone] = m_average_v[zone] / m_average_counter[zone]
      else
          m_average_v[zone] = AtmoSetup_DarknessLimit;
  }

  */

  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    if(m_average_counter[zone] > 0)
       m_average_v[zone] = m_average_v[zone] / m_average_counter[zone];
    else
       m_average_v[zone] = AtmoSetup_DarknessLimit;

    m_average_v[zone] = (int)((float)m_average_v[zone] * ((float)AtmoSetup_BrightCorrect / 100.0));

    hsv_pixel.v = (unsigned char)ATMO_MAX(ATMO_MIN(m_average_v[zone],255),0);
    hsv_pixel.h = m_most_used_hue[zone];
    hsv_pixel.s = m_most_used_sat[zone];

    // convert back to rgb
    output_colors->zone[zone] = HSV2RGB(hsv_pixel);
  }


  return output_colors;
}