/*==============================================================================
  RichEditor Demo with footnotes, endnotes and print preview.
  See "Notes" main menu.
==============================================================================*/
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "PreviewFrm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "RichView"
#pragma link "RVEdit"
#pragma link "RVScroll"
#pragma link "RVStyle"
#pragma link "PtblRV"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
// Parameters for ApplyStyleConversion
#define TEXT_BOLD          1
#define TEXT_ITALIC        2
#define TEXT_UNDERLINE     3
#define TEXT_APPLYFONTNAME 4
#define TEXT_APPLYFONT     5
#define TEXT_APPLYFONTSIZE 6
#define TEXT_COLOR         7
#define TEXT_BACKCOLOR     8
// Parameters for ApplyParaStyleConversion
#define PARA_ALIGNMENT     1
#define PARA_INDENTINC     2
#define PARA_INDENTDEC     3
#define PARA_COLOR         4
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  // Filling font names combobox
  cmbFont->Items->Assign(Screen->Fonts);
  ActiveEditor = rveMain;
  New();
}
//---------------------------------------------------------------------------
// Document in rveMain or rveNote was changed
void __fastcall TForm1::rveChange(TObject *Sender)
{
  StatusBar1->SimpleText = "Modified";
}
//---------------------------------------------------------------------------
// Current text style in rveMain or rveNote was changed
void __fastcall TForm1::rveCurTextStyleChanged(TObject *Sender)
{
  TCustomRichViewEdit* rve = ((TCustomRichViewEdit*)Sender)->GetRootEditor();
  if (rve!=ActiveEditor)
    return;
  IgnoreChanges = true;
  // Changing selection in comboboxes with font names and sizes:
  TFontInfo* fi = rvs->TextStyles->Items[rve->CurTextStyleNo];
  cmbFont->ItemIndex = cmbFont->Items->IndexOf(fi->FontName);
  cmbFontSize->Text = IntToStr(fi->Size);

  // Checking font buttons
  btnBold->Down      = fi->Style.Contains(fsBold);
  btnItalic->Down    = fi->Style.Contains(fsItalic);
  btnUnderline->Down = fi->Style.Contains(fsUnderline);
  IgnoreChanges = false;
}
//---------------------------------------------------------------------------
// Current paragraph style in rveMain or rveNote was changed
void __fastcall TForm1::rveCurParaStyleChanged(TObject *Sender)
{
  TCustomRichViewEdit* rve = ((TCustomRichViewEdit*)Sender)->GetRootEditor();
  if (rve!=ActiveEditor)
    return;
  SetAlignmentToUI(rvs->ParaStyles->Items[rve->CurParaStyleNo]->Alignment);
}
//--------------------------------------------------------------------------
// Returns paragraph alignment selected in the toolbar
TRVAlignment TForm1::GetAlignmentFromUI()
{
  if (btnLeft->Down)
    return rvaLeft;
  else if (btnRight->Down)
    return rvaRight;
  else if (btnCenter->Down)
    return rvaCenter;
  else
    return rvaJustify;
}
//--------------------------------------------------------------------------
// Sets Alignment to the toolbar
void TForm1::SetAlignmentToUI(TRVAlignment Alignment)
{
  switch (Alignment)
  {
    case rvaLeft:
      btnLeft->Down = true;
      break;
    case rvaCenter:
      btnCenter->Down = true;
      break;
    case rvaRight:
      btnRight->Down = true;
      break;
    case rvaJustify:
      btnJustify->Down = true;
      break;
  }
}
//---------------------------------------------------------------------------
// Applying font name to ActiveEditor
void __fastcall TForm1::cmbFontClick(TObject *Sender)
{
  if (cmbFont->ItemIndex!=-1 && !IgnoreChanges)
  {
    FontName = cmbFont->Items->Strings[cmbFont->ItemIndex];
    ActiveEditor->ApplyStyleConversion(TEXT_APPLYFONTNAME);
  }
  if (Visible)
    ActiveEditor->SetFocus();
}
//---------------------------------------------------------------------------
// Applying font size to ActiveEditor
void __fastcall TForm1::cmbFontSizeClick(TObject *Sender)
{
  if (cmbFontSize->Text!="" && !IgnoreChanges)
  {
    FontSize = StrToIntDef(cmbFontSize->Text, 10);
    ActiveEditor->ApplyStyleConversion(TEXT_APPLYFONTSIZE);
  }
  if (Visible)
    ActiveEditor->SetFocus();
}
//---------------------------------------------------------------------------
// Applying bold/italic/underline to ActiveEditor
void __fastcall TForm1::FontStyleButtonClick(TObject *Sender)
{
  TSpeedButton*Button = (TSpeedButton*)Sender;
  // constants TEXT_BOLD, TEXT_ITALIC and TEXT_UNDERLINE are
  // assigned to the tags of corresponding buttons
  ActiveEditor->ApplyStyleConversion(Button->Tag);
}
//---------------------------------------------------------------------------
// Applying font to ActiveEditor
void __fastcall TForm1::mitFontClick(TObject *Sender)
{
  fd->Font->Assign(rvs->TextStyles->Items[ActiveEditor->CurTextStyleNo]);
  if (fd->Execute())
    ActiveEditor->ApplyStyleConversion(TEXT_APPLYFONT);
}
//---------------------------------------------------------------------------
// Applying text color to ActiveEditor
void __fastcall TForm1::btnFontColorClick(TObject *Sender)
{
  cd->Color = rvs->TextStyles->Items[ActiveEditor->CurTextStyleNo]->Color;
  if (cd->Execute())
    ActiveEditor->ApplyStyleConversion(TEXT_COLOR);
}
//---------------------------------------------------------------------------
// Applying text background color to ActiveEditor
void __fastcall TForm1::btnFontBackColorClick(TObject *Sender)
{
  switch (Application->MessageBox(
	L"Make the selected text background transparent?\n"
	L"(YES - make transparent; NO - choose color)",
	L"Text Background", MB_YESNOCANCEL | MB_ICONQUESTION))
  {
    case IDYES:
      cd->Color = clNone;
      break;
    case IDNO:
      cd->Color = rvs->TextStyles->Items[ActiveEditor->CurTextStyleNo]->BackColor;
        if (cd->Color==clNone)
          cd->Color = clWhite;
        if (! cd->Execute())
          return;
      break;
    case IDCANCEL:
      return;
  }
  ActiveEditor->ApplyStyleConversion(TEXT_BACKCOLOR);
}
//---------------------------------------------------------------------------
// Applying paragraph background color to ActiveEditor
void __fastcall TForm1::btnParaBackColorClick(TObject *Sender)
{
  switch (Application->MessageBox(
	L"Make the selected paragraph background transparent?\n"
	L"(YES - make transparent; NO - choose color)",
	L"Text Background", MB_YESNOCANCEL | MB_ICONQUESTION))
  {
    case IDYES:
      cd->Color = clNone;
      break;
    case IDNO:
      cd->Color = rvs->ParaStyles->Items[ActiveEditor->CurParaStyleNo]->Background->Color;
      if (cd->Color==clNone)
        cd->Color = clWhite;
      if (! cd->Execute())
        return;
      break;
    case IDCANCEL:
      return;
  }
  ActiveEditor->ApplyParaStyleConversion(PARA_COLOR);
}
//---------------------------------------------------------------------------
// Applying paragraph alignment to ActiveEditor
void __fastcall TForm1::btnApplyPara(TObject *Sender)
{
   ActiveEditor->ApplyParaStyleConversion(PARA_ALIGNMENT);
}
//---------------------------------------------------------------------------
// Changing left indents in ActiveEditor
void __fastcall TForm1::btnIdentDecClick(TObject *Sender)
{
  ActiveEditor->ApplyParaStyleConversion(PARA_INDENTDEC);
}

void __fastcall TForm1::btnIdentIncClick(TObject *Sender)
{
  ActiveEditor->ApplyParaStyleConversion(PARA_INDENTINC);
}
//---------------------------------------------------------------------------
// rveMain's & rveNote's OnStyleConversion
void __fastcall TForm1::rveStyleConversion(TCustomRichViewEdit *Sender,
      int StyleNo, int UserData, bool AppliedToText, int &NewStyleNo)
{
  TFontInfo* FontInfo = new TFontInfo(NULL);
  FontInfo->Assign(rvs->TextStyles->Items[StyleNo]);
  switch (UserData)
  {
    case TEXT_BOLD:
    {
      if (btnBold->Down)
        FontInfo->Style << fsBold;
      else
        FontInfo->Style >> fsBold;
      break;
    }
    case TEXT_ITALIC:
    {
      if (btnItalic->Down)
        FontInfo->Style << fsItalic;
      else
        FontInfo->Style >> fsItalic;
      break;
    }
    case TEXT_UNDERLINE:
    {
      if (btnUnderline->Down)
        FontInfo->Style << fsUnderline;
      else
        FontInfo->Style >> fsUnderline;
      break;
    }
    case TEXT_APPLYFONTNAME:
      FontInfo->FontName = FontName;
      break;
    case TEXT_APPLYFONTSIZE:
      FontInfo->Size     = FontSize;
      break;
    case TEXT_APPLYFONT:
      FontInfo->Assign(fd->Font);
      break;
    case TEXT_COLOR:
      FontInfo->Color = cd->Color;
      break;
    case TEXT_BACKCOLOR:
      FontInfo->BackColor = cd->Color;
      break;
      // add your code here....
  }
  NewStyleNo = rvs->TextStyles->FindSuchStyle(StyleNo,FontInfo,RVAllFontInfoProperties);
  if (NewStyleNo<0)
  {
    rvs->TextStyles->Add();
    NewStyleNo = rvs->TextStyles->Count-1;
    rvs->TextStyles->Items[NewStyleNo]->Assign(FontInfo);
    rvs->TextStyles->Items[NewStyleNo]->Standard = false;
  }
  delete FontInfo;
}
//---------------------------------------------------------------------------
// rveMain's & rveNote's OnParaStyleConversion
void __fastcall TForm1::rveParaStyleConversion(TCustomRichViewEdit *Sender,
	int StyleNo, int UserData, bool AppliedToText, int &NewStyleNo)
{
  TParaInfo* ParaInfo = new TParaInfo(NULL);
  ParaInfo->Assign(rvs->ParaStyles->Items[StyleNo]);
  switch (UserData)
  {
    case PARA_ALIGNMENT:
      ParaInfo->Alignment = GetAlignmentFromUI();
      break;
    case PARA_INDENTINC:
      ParaInfo->LeftIndent = ParaInfo->LeftIndent+20;
      if (ParaInfo->LeftIndent>200)
        ParaInfo->LeftIndent = 200;
      break;
    case PARA_INDENTDEC:
      ParaInfo->LeftIndent = ParaInfo->LeftIndent-20;
      if (ParaInfo->LeftIndent<0)
        ParaInfo->LeftIndent = 0;
      break;
    case PARA_COLOR:
      ParaInfo->Background->Color = cd->Color;
      break;
    // add your code here....
  }
  NewStyleNo = rvs->ParaStyles->FindSuchStyle(StyleNo,ParaInfo,RVAllParaInfoProperties);
  if (NewStyleNo<0)
  {
    rvs->ParaStyles->Add();
    NewStyleNo = rvs->ParaStyles->Count-1;
    rvs->ParaStyles->Items[NewStyleNo]->Assign(ParaInfo);
    rvs->ParaStyles->Items[NewStyleNo]->Standard = false;
  }
  delete ParaInfo;
}
//---------------------------------------------------------------------------
// cmbFontSize combobox: Enter key triggers OnClick
void __fastcall TForm1::cmbFontSizeKeyPress(TObject *Sender, wchar_t &Key)
{
  if (Key==VK_RETURN)
  {
    Key = 0;
    cmbFontSizeClick(NULL);
  }
}
//---------------------------------------------------------------------------
// cmbFontSize combobox: moving focus from it triggers OnClick
void __fastcall TForm1::cmbFontSizeExit(TObject *Sender)
{
  cmbFontSizeClick(NULL);
}
//---------------------------------------------------------------------------
// Menu Edit | Undo
void __fastcall TForm1::mitUndoClick(TObject *Sender)
{
  ActiveEditor->Undo();
}
//---------------------------------------------------------------------------
// Menu Edit | Rendo
void __fastcall TForm1::mitRedoClick(TObject *Sender)
{
  ActiveEditor->Redo();
}
//---------------------------------------------------------------------------
// Menu Edit | Cut
void __fastcall TForm1::mitCutClick(TObject *Sender)
{
  ActiveEditor->CutDef();
}
//---------------------------------------------------------------------------
// Menu Edit | Copy
void __fastcall TForm1::mitCopyClick(TObject *Sender)
{
  ActiveEditor->CopyDef();
}
//---------------------------------------------------------------------------
// Menu Edit | Paste
void __fastcall TForm1::mitPasteClick(TObject *Sender)
{
  ActiveEditor->Paste();
}
//---------------------------------------------------------------------------
// Menu Edit | Delete
void __fastcall TForm1::mitDeleteClick(TObject *Sender)
{
  ActiveEditor->DeleteSelection();
}
//---------------------------------------------------------------------------
/* Saves note text (if it was edited) in the main document, then asks user
  to save the document.
  Returns true if:
  - the user answers "No", or
  - the user answers "Yes" and the document was saved.
  Returns false if:
  - the user answers "Cancel", or
  - the user answers "Yes" and the document was not saved. */
bool TForm1::SaveIfNeeded()
{
  UpdateNote();
  if (rveMain->Modified)
	switch (Application->MessageBox(
	  L"Save file now?", L"File was modified", MB_ICONQUESTION | MB_YESNOCANCEL))
    {
      case IDYES:
        return Save();
      case IDNO:
        return true;
      default: //case IDCANCEL:
        return false;
    }
  else
    return true;
}
//---------------------------------------------------------------------------
// Saves the document. If this is a new document, calls SaveAs().
//  Returns true on successful saving
bool TForm1::Save()
{
  if (FileName=="")
    return SaveAs();
  else
  {
    UpdateNote();
    bool r = false;
    switch (FileFormat)
    {
      case dffRVF:
        r = rveMain->SaveRVF(FileName, false);
        break;
      case dffRTF:
        r = rveMain->SaveRTF(FileName, false);
        break;
    }
    if (r)
    {
      rveMain->Modified = false;
      StatusBar1->SimpleText = "";
      return true;
    }
    else
    {
      Application->MessageBox(L"Cannot save file", L"Error", MB_OK | MB_ICONSTOP);
      return SaveAs();
    }
  }
}
//---------------------------------------------------------------------------
// Displays save dialog and calls Save() to save document.
// Returns true on successful saving
bool TForm1::SaveAs()
{
  sd->FileName = FileName;
  sd->FilterIndex = (int)(FileFormat+1);
  if (sd->Execute())
  {
    FileName = sd->FileName;
    FileFormat =(TDemoFileFormat)(sd->FilterIndex-1);
    bool r = Save();
    if (r)
      Caption = ExtractFileName(FileName) + "- RDemo";
    return r;
  }
  else
    return false;
}
//---------------------------------------------------------------------------
// Asks to save the existing document.
// Opens document from file
void TForm1::Open()
{
  if (!SaveIfNeeded())
    return;
  rveMain->Modified = false;
  New();
  if (od->Execute())
  {
    bool r = false;
    DisableNote();
    rveMain->Clear();
    rveMain->DeleteUnusedStyles(true, true, true);
    FileName = od->FileName;
    switch (od->FilterIndex)
    {
      case 1:
        r = rveMain->LoadRVF(FileName);
        FileFormat = dffRVF;
        break;
      case 2:
        r = rveMain->LoadRTF(FileName);
        FileFormat = dffRTF;
        break;
    }
    rveMain->Format();
    rveCurTextStyleChanged(ActiveEditor);
    rveCurParaStyleChanged(ActiveEditor);
    DisableNote(true);
    StatusBar1->SimpleText = "";
    Caption = ExtractFileName(FileName) + "- RDemo";
    if (!r)
      Application->MessageBox(L"Error while opening or reading file", L"Error",
        MB_OK | MB_ICONSTOP);
  }
}
//---------------------------------------------------------------------------
// Asks to save the existing document. Creates a new document
void TForm1::New()
{
  if (!SaveIfNeeded())
    return;
  FileName = "";
  FileFormat = dffRVF;
  StatusBar1->SimpleText = "";
  Caption = "Unnamed - RDemo";
  DisableNote(true);  
  rveMain->LeftMargin   = 5;
  rveMain->RightMargin  = 5;
  rveMain->TopMargin    = 5;
  rveMain->BottomMargin = 5;
  rveMain->BackgroundBitmap = NULL;
  rveMain->BackgroundStyle = bsNoBitmap;
  rveMain->Clear();
  rveMain->DeleteUnusedStyles(true, true, true);
  rveMain->Format();
  rveCurTextStyleChanged(ActiveEditor);
  rveCurParaStyleChanged(ActiveEditor);
}
//---------------------------------------------------------------------------
// Menu File | New
void __fastcall TForm1::mitNewClick(TObject *Sender)
{
  New();
}
//---------------------------------------------------------------------------
// Menu File | Open
void __fastcall TForm1::mitOpenClick(TObject *Sender)
{
  Open();
}
//---------------------------------------------------------------------------
// Menu File | Save
void __fastcall TForm1::mitSaveClick(TObject *Sender)
{
  Save();
}
//---------------------------------------------------------------------------
// Menu File | Save As
void __fastcall TForm1::mitSaveAsClick(TObject *Sender)
{
  SaveAs();
}
//---------------------------------------------------------------------------
// Menu File | Print Preview
void __fastcall TForm1::mitPreviewClick(TObject *Sender)
{
  UpdateNote();
  RVPrint1->AssignSource(rveMain);
  RVPrint1->FormatPages(TRVDisplayOptions());
  TfrmPreview* frm = new TfrmPreview(Application);
  try
  {
    frm->rvpp->RVPrint = RVPrint1;
    frm->Button1Click(NULL);
    frm->ShowModal();
  }
  __finally
  {
    delete frm;
  }
  RVPrint1->Clear();
}
//---------------------------------------------------------------------------
// Menu File | Exit
void __fastcall TForm1::mitExitClick(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------
// Form1->OnCloseQuery
void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose)
{
  CanClose = SaveIfNeeded();
}
//---------------------------------------------------------------------------
// Occurs when input focus is set to rveMain
void __fastcall TForm1::rveMainEnter(TObject *Sender)
{
  ActiveEditor = rveMain;
  rveCurTextStyleChanged(ActiveEditor);
  rveCurParaStyleChanged(ActiveEditor);
  mitInsertEndnote->Enabled = true;
  mitInsertFootnote->Enabled = true;
  mitInsertNoteReference->Enabled = false;
}
//---------------------------------------------------------------------------
// Occurs when input focus is set to rveNote
void __fastcall TForm1::rveNoteEnter(TObject *Sender)
{
  ActiveEditor = rveNote;
  rveCurTextStyleChanged(ActiveEditor);
  rveCurParaStyleChanged(ActiveEditor);
  mitInsertEndnote->Enabled = false;
  mitInsertFootnote->Enabled = false;
  mitInsertNoteReference->Enabled = true;
}
//---------------------------------------------------------------------------
// Disables rveNote
void TForm1::DisableNote(bool Init)
{
  if (Init || FActiveNoteItem)
  {
    FActiveNoteItem = NULL;
    rveNote->Enabled = false;
    rveNote->Color = clBtnFace;
    rveNote->Clear();
    rveNote->AddNLWTag(L"(footnote or endnote is not selected)", 0, 0, 0);
    rveNote->Format();
  }
}
//---------------------------------------------------------------------------
// Starts editing NoteItem's Document in rveNote
void TForm1::EditNote(TCustomRVNoteItemInfo* NoteItem)
{
  if (FActiveNoteItem == NoteItem)
    return;
  FActiveNoteItem = NoteItem;
  rveNote->NoteText = NoteItem->Text; // this text is displayed in
                                      // TRVNoteReferenceItemInfo items
  rveNote->Enabled = true;
  rveNote->Color = clWindow;
  rveNote->Clear();
  TMemoryStream* Stream = new TMemoryStream;
  try
  {
    NoteItem->Document->SaveRVFToStream(Stream);
    Stream->Position = 0;
    rveNote->LoadRVFFromStream(Stream);
  }
  __finally
  {
    delete Stream;
  }
  rveNote->Format();
  int LastItemNo = rveNote->ItemCount-1;
  rveNote->SetSelectionBounds(LastItemNo, rveNote->GetOffsAfterItem(LastItemNo),
      LastItemNo, rveNote->GetOffsAfterItem(LastItemNo));
}
//---------------------------------------------------------------------------
// Saves changes made in rveNote to FActiveNoteItem.Document. This operation
// can be undone and redone by the user
void TForm1::UpdateNote()
{
  if (!rveNote->Modified)
    return;
  TMemoryStream* Stream = new TMemoryStream;
  try
  {
    rveNote->SaveRVFToStream(Stream, false);
    FActiveNoteItem->ReplaceDocumentEd(Stream); // this is an editing operation
                                                // in rveMain, can be undone by user
  }
  __finally
  {
    delete Stream;
  }
  rveNote->Modified = false;
}
//---------------------------------------------------------------------------
// Menu Notes | Insert Endnote.
//  This command is enabled only if ActiveEditor == rveMain.
//  This command inserts a new endnote in rveMain. In the endnote document, it
//  adds the note reference (TRVNoteReferenceItemInfo, displays endnote number)
//  and one space character. Because of rveMain->CaretMove, this endnote will be
//  immediately opened in rveNote.
//  Moving input focus to rveNote.
void __fastcall TForm1::mitInsertEndnoteClick(TObject *Sender)
{
  TRVEndnoteItemInfo* EndNote = new TRVEndnoteItemInfo(rveMain->RVData,
    RVGetNoteTextStyleNo(rvs, rveMain->CurTextStyleNo), 1, false);
  TRVNoteReferenceItemInfo* NoteRef = new TRVNoteReferenceItemInfo(EndNote->Document,
    RVGetNoteTextStyleNo(rvs,0));
  EndNote->Document->AddItem("", NoteRef);
  EndNote->Document->AddNLWTag(L" ", 0, -1, 0);
  if (rveMain->InsertItem("", EndNote))
    rveNote->SetFocus();
}
//---------------------------------------------------------------------------
// Menu Notes | Insert Footnote.
void __fastcall TForm1::mitInsertFootnoteClick(TObject *Sender)
{
  TRVFootnoteItemInfo* FootNote = new TRVFootnoteItemInfo(rveMain->RVData,
    RVGetNoteTextStyleNo(rvs, rveMain->CurTextStyleNo), 1, false);
  TRVNoteReferenceItemInfo* NoteRef = new TRVNoteReferenceItemInfo(FootNote->Document,
    RVGetNoteTextStyleNo(rvs,0));
  FootNote->Document->AddItem("", NoteRef);
  FootNote->Document->AddNLWTag(L" ", 0, -1, 0);
  if (rveMain->InsertItem("", FootNote))
    rveNote->SetFocus();
}
//---------------------------------------------------------------------------
// Menu Notes | Insert Footnote/Endnote Number.
//  This command is enabled only if ActiveEditor == rveNote.
//  Inserts note reference (TRVNoteReferenceItemInfo, displays endnote number) in
//  rveNote.
//  This command is not really necessary, but may be useful if the user acidentally
//  deleted the initial reference
void __fastcall TForm1::mitInsertNoteReferenceClick(TObject *Sender)
{
  TRVNoteReferenceItemInfo* NoteRef = new TRVNoteReferenceItemInfo(rveNote->RVData,
    RVGetNoteTextStyleNo(rvs,rveNote->CurTextStyleNo));
  rveNote->InsertItem("", NoteRef);
}
//---------------------------------------------------------------------------
// rveMain->OnCaretMove. Updates rveNote
void __fastcall TForm1::rveMainCaretMove(TObject *Sender)
{
  if (rveMain->GetCurrentItem()->InheritsFrom(__classid(TCustomRVNoteItemInfo)))
    EditNote((TCustomRVNoteItemInfo*)rveMain->GetCurrentItem());
  else
  {
    UpdateNote();
    DisableNote();
  }
}
//---------------------------------------------------------------------------
// When moving input focus from rveNote, we update note document (if it was edited)
void __fastcall TForm1::rveNoteExit(TObject *Sender)
{
  UpdateNote();        
}
//---------------------------------------------------------------------------

