/*==============================================================================
{
  Mail merge application: part 2 - displaying processed template.

  How it works:
  - RVStyle2 has two predefined styles (the same as in the template editor;
    1th text style is reserved for fields).
  - RichView1 and RichView2 are linked to the same RVStyle (RVStyle2)
  - Template is loaded in RichView1 (styles can be added dynamically in RVStyle2)
  - RichView1 is scanned for fields. When field is found, it is deleted,
    and its value is inserted in its place:
    * field value is loaded in invisible RichView2 (styles can be added in RVStyle2)
    * contents of RichView2 is inserted in the proper place of RichView1.
}
==============================================================================*/

#include <vcl.h>
#pragma hdrstop

#include "MMMainFrm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "RichView"
#pragma link "RVScroll"
#pragma link "RVStyle"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  // Loading template with fields
  RichView1->LoadRVF(ExtractFilePath(Application->ExeName)+"Template.rvf");
  // RVData->InsertFromStream() (we will call it later) does not support
  // style merging. So changing mode to style ignoring:
  RichView1->RVFParaStylesReadMode = rvf_sIgnore;
  RichView1->RVFTextStylesReadMode = rvf_sIgnore;
  // Replace styles with values
  ReplaceFields(RichView1->RVData);
  RichView1->Format();
}
//---------------------------------------------------------------------------
void TForm1::ReplaceFields(TCustomRVFormattedData* RVData)
{
  TColor Dummy1 = clNone;
  TRVBackground * Dummy2 = NULL;
  TRVLayoutInfo * Dummy3 = NULL;
  for (int i=RVData->ItemCount-1; i>=0; i--)
  {
    switch (RVData->GetItemStyle(i))
    {
      case 1: // the first text style is used for fields
      {
        // storing parameters of deleted items
        int ParaNo = RVData->GetItemPara(i);
        bool BR    = RVData->GetItem(i)->BR;
        bool ContinuePara = RVData->GetItem(i)->SameAsPrev;
        // loading field value in the stream
        TMemoryStream* Stream;
        LoadData(RVData->GetItemTextA(i), Stream);
        if (Stream)
        {
          // deleting the field code
          RVData->DeleteItems(i,1);
          // inserting the field value
          RVData->InsertRVFFromStream(Stream, i, Dummy1, Dummy2, Dummy3, false);
          // applying stored parameters to the inserted items
          if (i>0 && RVData->GetItemStyle(i-1)==rvsListMarker &&
            RVData->GetItemStyle(i)==rvsListMarker)
            RVData->DeleteItems(i, 1);
          for (int j = i; j<RVData->ItemCount; j++)
          {
            if (i==j)
            {
              if (RVData->GetItem(j)->GetBoolValue(rvbpFullWidth))
              {
                if (i>0 && RVData->GetItemStyle(i-1)==rvsListMarker)
                {
                   i--;
                   RVData->DeleteItems(i, 1);
                }
                break;
              }
              RVData->GetItem(j)->SameAsPrev = ContinuePara;
              if (BR)
                RVData->GetItem(j)->BR = true;
            }
            if (j>i && RVData->IsParaStart(j))
              break;
            RVData->GetItem(j)->ParaNo = ParaNo;
          }
          delete Stream;
        }
        break;
      }
      case rvsTable:
      {
        // recursive call for table cells
        TRVTableItemInfo* table = (TRVTableItemInfo*)(RVData->GetItem(i));
        for (int r=0; r<table->Rows->Count; r++)
          for (int c=0; c<table->Rows->Items[r]->Count; c++)
            if (table->Cells[r][c])
              ReplaceFields(table->Cells[r][c]);
        break;
      }
    }
  }
  RVData->Normalize();
}
//---------------------------------------------------------------------------
// Loading field code
void TForm1::LoadData(const AnsiString Code, TMemoryStream* &Stream)
{
  TLocateOptions SearchOptions;
  if (! Table1->Locate("Code", Code, SearchOptions))
    return;
  Stream = new TMemoryStream;
  ((TBlobField*)(Table1->FieldByName("Data")))->SaveToStream(Stream);
  Stream->Position = 0;
  RichView2->Clear();
  RichView2->InsertRVFFromStream(Stream, 0); // inserting will merge styles;
    // RichView1 and RichView2 have the same collections of styles
  Stream->Clear();
  RichView2->SaveRVFToStream(Stream, false);
  Stream->Position = 0;
  return;
}
