(************************************************************************
 *                                                                      *
 *   Ant Movie Catalog 4.x                                              *
 *   (C) 2005-2006 Antoine Potten                                       *
 *   http://www.antp.be/software                                        *
 *                                                                      *
 ************************************************************************
 *                                                                      *
 *   This program is free software; you can redistribute it and/or      *
 *   modify it under the terms of the GNU General Public License        *
 *   as published by the Free Software Foundation; either version 2     *
 *   of the License, or (at your option) any later version.             *
 *                                                                      *
 *   This program is distributed in the hope that it will be useful,    *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 *   GNU General Public License for more details.                       *
 *                                                                      *
 ************************************************************************)

unit import2_frame;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, ActnList, Contnrs,

  TBXDkPanels,
  AntStringList, AntJvLinkLabel,

  MovieClass, import2_engines, TB2Item, TBX, Menus;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

type
  TImportFrame = class(TFrame)
    grpSettings: TGroupBox;
    grpPreview: TGroupBox;
    grpSourceFile: TGroupBox;
    PanelTop: TPanel;
    lblLink: TAntJvLinkLabel;
    btnReload: TTBXButton;
    btnBrowse: TTBXButton;
    edtSourceFile: TEdit;
    chkAllowDup: TCheckBox;
    chkAutoAssign: TCheckBox;
    lstPreview: TListView;
    lblPreview: TLabel;
    ActionList1: TActionList;
    ActionListAll: TAction;
    ActionListCheck: TAction;
    ActionListNone: TAction;
    ActionListUncheck: TAction;
    MenuPopupList: TTBXPopupMenu;
    MnuLspChk: TTBXItem;
    MnuLspUnc: TTBXItem;
    MnuLsp__1: TTBXSeparatorItem;
    MnuLspAll: TTBXItem;
    MnuLspNon: TTBXItem;
    MenuPopupHeader: TTBXPopupMenu;
    ActionHeaderNoImport: TAction;
    MnuHdpNot: TTBXItem;
    lblPictures: TLabel;
    cmbPictures: TComboBox;
    Messages: TAntStringList;
    MnuMov: TTBXSubmenuItem;
    MnuMovCF: TTBXSubmenuItem;
    procedure lblLinkLinkClick(Sender: TObject; LinkNumber: Integer; LinkText: String);
    procedure btnBrowseClick(Sender: TObject);
    procedure btnReloadClick(Sender: TObject);
    procedure ActionListCheckExecute(Sender: TObject);
    procedure ActionHeaderClick(Sender: TObject);
    procedure lstPreviewColumnClick(Sender: TObject; Column: TListColumn);
  private
    procedure SetCatalogFile(const ACatalogFile: TFileName);
  protected
    FImportEngine: TImportEngine;
    FImportType: string;
    FCatalogFile: TFileName;
    FCatalogPath: TFileName;
  public
    Properties: TCustomFieldsProperties; // ref
    constructor Create(Owner: TComponent; Engine: TImportEngine;
      const ImportType: string; CustomFieldsProperties: TCustomFieldsProperties); reintroduce;
    destructor Destroy; override;
    property ImportEngine: TImportEngine read FImportEngine;
    procedure LoadSettings; virtual;
    procedure SaveSettings; virtual;
    procedure ImportToList(AList: TMovieList);
    procedure ImportPicture(SourceMovie, NewMovie: TMovie; FieldValue: string; CopiedPictures: TStrings);
  published
    property CatalogFile: TFileName read FCatalogFile write SetCatalogFile;
  end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

implementation

{$R *.dfm}

uses
  Global, ConstValues, functions_files, fields, functions_gui,
  ProgramSettings, functions_tbx, ComboBoxAutoWidth;

const
  msgNoMovie = 0;
  msgNoColumn = 1;
  msgNoCatalogName = 2;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

constructor TImportFrame.Create(Owner: TComponent; Engine: TImportEngine;
  const ImportType: string; CustomFieldsProperties: TCustomFieldsProperties);
var
  i: Integer;
  NewItem: TTBXItem;
begin
  inherited Create(Owner);
  LoadButtonIcon(btnBrowse, ICON_BROWSE);
  LoadButtonIcon(btnReload, ICON_REFRESH, False);
  Font.Name := Graphics.DefFontData.Name;
  Font.Charset := Graphics.DefFontData.Charset;
  Properties := CustomFieldsProperties; // ref

  // Movie fields
  for i := fieldLow to fieldCount - 1 do
    if not (i in VirtualFields) then
    begin
      NewItem := TTBXItem.Create(MnuMov);
      NewItem.Caption := strFields[i];
      NewItem.Tag := i;
      NewItem.OnClick := ActionHeaderClick;
      NewItem.GroupIndex := 1;
      MnuMov.Add(NewItem);
    end;
  // Picture
  NewItem := TTBXItem.Create(MnuMov);
  NewItem.Caption := strFieldPicture;
  NewItem.Tag := fieldPicture;
  NewItem.OnClick := ActionHeaderClick;
  NewItem.GroupIndex := 1;
  MnuMov.Add(NewItem);
  // Custom fields
  with Properties do
    for i := 0 to Count-1 do
    begin
      NewItem := TTBXItem.Create(MnuMovCF);
      NewItem.Caption := Objects[i].FieldName;
      NewItem.Tag := i + customFieldLow;
      NewItem.OnClick := ActionHeaderClick;
      NewItem.GroupIndex := 2;
      MnuMovCF.Add(NewItem);
    end;

  FImportEngine := Engine;
  FImportType := ImportType;
  Translator.Translate(Self);
  if FImportEngine.GetURL <> '' then
    lblLink.Caption := Format(lblLink.Caption, [Format('<link>%s</link>', [FImportEngine.FormatName])])
  else
    lblLink.Caption := Format(lblLink.Caption, [FImportEngine.FormatName]);
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

destructor TImportFrame.Destroy;
begin
  FreeAndNil(FImportEngine);
  inherited;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.lblLinkLinkClick(Sender: TObject; LinkNumber: Integer; LinkText: String);
begin
  LaunchProg(FImportEngine.GetURL);
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.btnBrowseClick(Sender: TObject);
begin
  with TOpenDialog.Create(Self) do
    try
      Filter := FImportEngine.GetFilter;
      InitialDir := ExtractFilePath(edtSourceFile.Text);
      if not DirectoryExists(InitialDir) then
        InitialDir := '';
      FileName := ExtractFileName(edtSourceFile.Text);
      Options := DialogOpenOptions;
      if Execute then
      begin
        edtSourceFile.Text := FileName;
        btnReload.Click;
      end;
    finally
      Free;
    end;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.btnReloadClick(Sender: TObject);
begin
  SetWaitCursor;
  try
    SaveSettings;
    FImportEngine.Import(edtSourceFile.Text, lstPreview);
  finally
    RestoreCursor;
  end;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.ActionListCheckExecute(Sender: TObject);
var
  State, All: Boolean;
  i: Integer;
begin
  State := (Sender = ActionListCheck) or (Sender = actionListAll);
  All := (Sender = ActionListAll) or (Sender = ActionListNone);
  for i := 0 to lstPreview.Items.Count-1 do
    if All or lstPreview.Items[i].Selected then
      lstPreview.Items[i].Checked := State;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.ActionHeaderClick(Sender: TObject);
begin
  if Sender is TTBXItem then
    with lstPreview.Columns[lstPreview.Tag] do
    begin
      Tag := TTBXItem(Sender).Tag;
      if (Tag >= FieldLow) and (Tag < FieldCount) then
        Caption := strFields[TTBXItem(Sender).Tag]
      else if Tag = fieldPicture then
        Caption := strFieldPicture
      else if (Tag >= customFieldLow) and (Tag - customFieldLow < Properties.Count) then
        Caption := Properties.Objects[Tag - customFieldLow].FieldName
      else
      begin
        Tag := -1;
        Caption := '';
      end;
    end
  else
  if Sender = ActionHeaderNoImport then
    with lstPreview.Columns[lstPreview.Tag] do
    begin
      Tag := -1;
      Caption := '';
    end;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.lstPreviewColumnClick(Sender: TObject; Column: TListColumn);
var
  i: Integer;
  PicAssigned: Boolean;
  FieldsAssigned: TMovieFields;
  CustomFieldsAssigned: TMovieFields;
  Item: TTBXItem;
begin
  PicAssigned := False;
  FieldsAssigned := [];
  CustomFieldsAssigned := [];
  for i := 0 to lstPreview.Columns.Count - 1 do
  begin
    if lstPreview.Columns[i].Tag = fieldPicture then
      PicAssigned := True
    else if lstPreview.Columns[i].Tag in AllFields then
      Include(FieldsAssigned, lstPreview.Columns[i].Tag)
    else if (lstPreview.Columns[i].Tag >= customFieldLow) and
      (Tag - customFieldLow < Properties.Count) then
      Include(CustomFieldsAssigned, lstPreview.Columns[i].Tag);
  end;
  for i := 0 to MnuMov.Count-1 do
  begin
    Item := MnuMov.Items[i] as TTBXItem;
    Item.Checked := Column.Tag = Item.Tag;
    if Item.Tag = fieldPicture then
      Item.Enabled := not PicAssigned
    else
      Item.Enabled := not (Item.Tag in FieldsAssigned);
  end;
  for i := 0 to MnuMovCF.Count-1 do
  begin
    Item := MnuMovCF.Items[i] as TTBXItem;
    Item.Checked := Column.Tag = Item.Tag;
    Item.Enabled := not (Item.Tag in CustomFieldsAssigned);
  end;
  lstPreview.Tag := Column.Index;
  MenuPopupHeader.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.LoadSettings;
var
  s: string;
begin
  with Settings.rImport do
  begin
    chkAllowDup.Checked := AllowDup;
    chkAutoAssign.Checked := AutoAssign;
    cmbPictures.ItemIndex := PicImport;
    s := LastFiles.Values[FImportType];
    if FileExists(s) then
    begin
      edtSourceFile.Text := s;
//      btnReload.Click;
    end;
  end;
  //FitDropDownToContents(cmbPictures);
  SetComboxDropDownAutoWidth(cmbPictures);
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.SaveSettings;
begin
  with Settings.rImport do
  begin
    AllowDup := chkAllowDup.Checked;
    AutoAssign := chkAutoAssign.Checked;
    PicImport := cmbPictures.ItemIndex;
    LastFiles.Values[FImportType] := edtSourceFile.Text;
  end;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.SetCatalogFile(const ACatalogFile: TFileName);
begin
  FCatalogFile := ACatalogFile;
  FCatalogPath := ExtractFilePath(FCatalogFile);
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.ImportToList(AList: TMovieList);
var
  i, c, MaxNum: Integer;
  Item: TListItem;
  SourceMovie, NewMovie: TMovie;
  Corresp: TFieldCorresps;
  AddedMovies: TList;
  CopiedPictures: TStringList;
  AllowDups: Boolean;
  Value: string;
  function GetFieldValue(const c: Integer): string;
  begin
    if c = 0 then
      Result := Item.Caption
    else
    if c-1 < Item.SubItems.Count then
      Result := Item.SubItems[c-1]
    else
      Result := '';
  end;
begin
  if (FCatalogFile = '') and (cmbPictures.ItemIndex in [1,2,4]) then
    raise Exception.Create(Messages.Strings[msgNoCatalogName]);
  c := 0;
  for i := 0 to lstPreview.Items.Count-1 do
    if lstPreview.Items[i].Checked then
    begin
      Inc(c);
      Break;
    end;
  if c = 0 then
    raise Exception.Create(Messages.Strings[msgNoMovie]);
  c := 0;
  for i := 0 to lstPreview.Columns.Count-1 do
    if lstPreview.Columns[i].Tag <> -1 then
    begin
      Inc(c);
      Break;
    end;
  if c = 0 then
    raise Exception.Create(Messages.Strings[msgNoColumn]);
  AllowDups := chkAllowDup.Checked;
  AddedMovies := TList.Create;
  CopiedPictures := TStringList.Create;
  try
    try
      ImportEngine.GetFieldCorresp(Corresp, lstPreview.Columns);
      SetCurrentDir(ExtractFilePath(edtSourceFile.Text));
      // for each movie
      for i := 0 to lstPreview.Items.Count-1 do
      begin
        Item := lstPreview.Items[i];
        if Item.Checked then
        begin
          SourceMovie := TMovie(Item.Data); // can be nil
          NewMovie := AList.Add;
          NewMovie.InitFields;
          // for each column
          for c := 0 to Length(Corresp)-1 do
          begin
            if Corresp[c].TargetField = fieldPicture then
              ImportPicture(SourceMovie, NewMovie, ImportEngine.AdjustValue(Corresp[c].TargetField, GetFieldValue(c)), CopiedPictures)
            else
            begin
              // copy field value
              if (SourceMovie <> nil) and (Corresp[c].SourceField <> -1) then
              begin
                if Corresp[c].SourceField < fieldCount then // Movie Field
                  Value := SourceMovie.GetFieldValue(Corresp[c].SourceField)
                else // Custom Field
                  Value := SourceMovie.CustomFields.GetFieldValue(SourceMovie.CustomFields.Properties.Strings[Corresp[c].SourceField - customFieldLow]);
                if Corresp[c].TargetField < fieldCount then // Movie Field
                  NewMovie.SetFieldValue(Corresp[c].TargetField, Value)
                else // Custom Field
                  NewMovie.CustomFields.SetFieldValue(Properties.Strings[Corresp[c].TargetField - customFieldLow], Value, False);
              end
              else if Corresp[c].TargetField <> -1 then
              begin
                if Corresp[c].TargetField < fieldCount then // Movie Field
                  NewMovie.SetFieldValue(Corresp[c].TargetField,
                    ImportEngine.AdjustValue(Corresp[c].TargetField, GetFieldValue(c)))
                else // CustomField
                  NewMovie.CustomFields.SetFieldValue(Properties.Strings[Corresp[c].TargetField - customFieldLow],
                    ImportEngine.AdjustValue(Corresp[c].TargetField, GetFieldValue(c)), False);
              end;
              // check for duplicates
              if (not AllowDups) and (Corresp[c].TargetField = fieldNumber) and (NewMovie.iNumber > 0) then
              begin
                if AList.Count(NewMovie.iNumber) > 1 then
                  NewMovie.iNumber := 0;
              end;
            end;
          end;
          AddedMovies.Add(NewMovie);
        end;
      end;
      if Settings.rOptions.rMovieInformation.FirstAvailable then
        MaxNum := MaxInt
      else
        MaxNum := AList.MaxNumber;
      for i := 0 to AddedMovies.Count - 1 do
      begin
        NewMovie := AddedMovies[i];
        if NewMovie.iNumber > 0 then
          Continue;
        if MaxNum < MaxInt then
        begin
          Inc(MaxNum);
          NewMovie.iNumber := MaxNum;
        end
        else
          NewMovie.iNumber := AList.FirstFreeNumber;
      end;
    except
      for i := AList.Count-1 downto 0 do
        if AddedMovies.IndexOf(AList[i]) <> -1 then
        begin
          AList[i].Free;
          AList.Delete(i);
        end;
      for i := CopiedPictures.Count-1 downto 0 do
        DeleteFile(CopiedPictures[i]);
      raise;
    end;
  finally
    AddedMovies.Free;
    CopiedPictures.Free;
  end;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

procedure TImportFrame.ImportPicture(SourceMovie, NewMovie: TMovie; FieldValue: string; CopiedPictures: TStrings);
  function GetNewName(const Ext: string): string;
  begin
    Result := '';
    case Settings.rOptions.rMovieInformation.rPicImport.Naming of
      1:  if NewMovie.iNumber > 0 then
            Result := IntToStr(NewMovie.iNumber) + Ext;
      2:  if NewMovie.GetFormattedTitle <> '' then
            Result := ValidateFileName(NewMovie.GetFormattedTitle) + Ext;
    else
      Result := ChangeFileExt(ExtractFileName(FieldValue), Ext);
    end;
    if Result = '' then
      Result := 'Picture' + Ext;
    if Settings.rOptions.rMovieInformation.rPicImport.CatalogPrefix then
      Result := Format('%s_%s', [ChangeFileExt(ExtractFileName(FCatalogFile), ''), Result]);
    Result := ExtractFileName(MakeUniqueFileName(FCatalogPath + Result, '_'));
  end;
  procedure CopyPictureFile;
  var
    NewName: string;
  begin
    NewName := GetNewName(ExtractFileExt(FieldValue));
    if CopyFile(PChar(FieldValue), PChar(FCatalogPath + NewName), False) then
    begin
      NewMovie.strPicture := NewName;
      CopiedPictures.Add(FCatalogPath + NewName);
    end;
  end;
  procedure CopyPictureStream;
  begin
    NewMovie.Picture := TMemoryStream.Create;
    SourceMovie.Picture.Position := 0;
    NewMovie.Picture.CopyFrom(SourceMovie.Picture, SourceMovie.Picture.Size);
    NewMovie.strPicture := SourceMovie.strPicture;
  end;
  procedure CopyPictureFileToStream;
  begin
    try
      NewMovie.Picture := TMemoryStream.Create;
      NewMovie.Picture.LoadFromFile(FieldValue);
      NewMovie.strPicture := ExtractFileExt(FieldValue);
    except
      FreeAndNil(NewMovie.Picture);
    end;
  end;
  procedure CopyPictureStreamToFile;
  var
    NewName: string;
  begin
    NewName := GetNewName(ExtractFileExt(FieldValue));
    try
      SourceMovie.Picture.SaveToFile(FCatalogPath + NewName);
      NewMovie.strPicture := NewName;
      CopiedPictures.Add(FCatalogPath + NewName);
    except
    end;
  end;
begin
  if (SourceMovie <> nil) then
  begin
    FieldValue := SourceMovie.strPicture;
    case cmbPictures.ItemIndex of
      0: {store}
        begin
          if SourceMovie.Picture <> nil then
            CopyPictureStream
          else
          if SourceMovie.strPicture <> '' then
            CopyPictureFileToStream
        end;
      1: {copy}
        begin
          if SourceMovie.Picture <> nil then
            CopyPictureStreamToFile
          else
          if SourceMovie.strPicture <> '' then
            CopyPictureFile
        end;
      2: {copy if not stored}
        begin
          if SourceMovie.Picture <> nil then
            CopyPictureStream
          else
          if SourceMovie.strPicture <> '' then
            CopyPictureFile
        end;
      3: {abs link}
        begin
          if SourceMovie.strPicture <> '' then
            NewMovie.strPicture := ExpandFileName(SourceMovie.strPicture)
        end;
      4: {rel link}
        begin
          if SourceMovie.strPicture <> '' then
            NewMovie.strPicture := ExtractRelativePath(FCatalogPath, SourceMovie.strPicture);
        end;
    end;
  end
  else
    case cmbPictures.ItemIndex of
      0: {store}
        if FieldValue <> '' then
          CopyPictureFileToStream;
      1, 2: {copy  & copy if not stored}
        if FieldValue <> '' then
          CopyPictureFile;
      3: {abs link}
        if FieldValue <> '' then
          NewMovie.strPicture := ExpandFileName(FieldValue);
      4: {rel link}
        if FieldValue <> '' then
          NewMovie.strPicture := ExtractRelativePath(FCatalogPath, ExpandFileName(FieldValue));
    end;
end;

{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}

end.
