/* ====================================================================
 * Copyright (c) 2003-2006, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

#ifndef _SC_MERGE_H
#define _SC_MERGE_H

#include "util/types.h"


class Merge
{
public:
  Merge( LineTarget* dst, DiffInfoModel* di ) : _dst(dst), _di(di), _notMerged(0)
  {
  }

  void merge()
  {
    TextModel* original = _di->getModel( DiffInfoModel::dmOriginal );
    TextModel* modified = _di->getModel( DiffInfoModel::dmModified );
    TextModel* latest   = _di->getModel( DiffInfoModel::dmLatest );

    DiffInfos& di = _di->getInfos();

    for( DiffInfos::iterator it = di.begin(); it != di.end(); it++ )
    {
      DiffInfo& i = *it;

      svn::Offset s = i.getBlockInfo().getStart();
      svn::Offset l = i.getBlockInfo().getLength();

      switch( i.getType() )
      {
      case ctCommon:
        {
          merge( original, s, l, ctCommon );
          i.setMergeType(msOriginal);
          break;
        }
      case ctConflictLatestModified:
        {
          merge( modified, s, l, ctConflictLatestModifiedMerged );
          i.setMergeType(msModified);
          break;
        }
      case ctConflictModifiedLatest:
        {
          merge( latest, s, l, ctConflictModifiedLatestMerged );
          i.setMergeType(msLatest);
          break;
        }
      case ctConflictOriginal:
        {
          merge( modified, s, l, ctConflictOriginalMerged );
          i.setMergeType(msModified);
          break;
        }
      case ctConflictAll:
        {
          merge( original, s, l, ctConflictAll );
          i.setMergeType(msNotMerged);
          _notMerged++;
          break;
        }
      default:
        {
          assert(false);
        }
      }
    }
  }

  void merge( TextModel* src, svn::Offset start, svn::Offset len, ConflictType type )
  {
    sc::Size /*svn::Offset*/ s = (sc::Size)start;
    for( sc::Size /*svn::Offset*/ i = 0; i < (sc::Size)len; i++ )
    {
      const Line& ol = src->getLine(s+i);


      // special handling for "emtpy" lines
      if( ol.isEmpty() )
      {
        if( ol.getType() & ctFlagEmpty )
        {
          Line nl( sc::String(ol.getStr()), ol.getBlockNr(), ConflictType(type|ctFlagEmpty) );
          _dst->addLine( nl );
        }
        continue;
      }
      

      Line nl( sc::String(ol.getStr()), ol.getBlockNr(), type );
      _dst->addLine( nl );
    }
  }

  int getNotMergedCnt() const
  {
    return _notMerged;
  }

private:
  LineTarget*    _dst;
  DiffInfoModel* _di;

  int            _notMerged;
};

#endif // _SC_MERGE_H
