unit Main;

interface

uses
  PKSTController, IdStack, PKSTconst,
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ComCtrls, AppEvnts, Menus, RXShell, ImgList,
  Buttons;

type
  TPKSTServerForm = class(TForm)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    TabSheet3: TTabSheet;
    lvConnected: TListView;
    btnSelect: TButton;
    btnPublish: TButton;
    lvUploads: TListView;
    lbedtUploads: TLabeledEdit;
    RxTrayIcon1: TRxTrayIcon;
    PopupMenu1: TPopupMenu;
    menuDisplay: TMenuItem;
    N4: TMenuItem;
    N5: TMenuItem;
    ApplicationEvents1: TApplicationEvents;
    Panel1: TPanel;
    BitBtnCancle: TBitBtn;
    BitBtnOK: TBitBtn;
    chkboxSelect: TCheckBox;
    edtPublishFiles: TEdit;
    barPublish: TProgressBar;
    BitBtnOpen: TBitBtn;
    BitBtnApply: TBitBtn;
    BitBtnStop: TBitBtn;
    Label1: TLabel;
    OpendlgPublish: TOpenDialog;
    lbGuid: TLabel;
    lbedtName: TLabeledEdit;
    TabSheet4: TTabSheet;
    Memo1: TMemo;
    Button1: TButton;
    chkboxCRC: TCheckBox;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    edtSchedule: TEdit;
    btnSchedule: TButton;
    Button3: TButton;
    Button4: TButton;
    btnSendSch: TButton;
    txtMsg: TMemo;
    Button6: TButton;
    OpenDlgSchedule: TOpenDialog;
    procedure N5Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ApplicationEvents1Minimize(Sender: TObject);
    procedure RxTrayIcon1DblClick(Sender: TObject);
    procedure menuDisplayClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnSelectClick(Sender: TObject);
    procedure btnPublishClick(Sender: TObject);
    procedure chkboxSelectClick(Sender: TObject);
    procedure edtPublishFilesChange(Sender: TObject);
    procedure lvUploadsData(Sender: TObject; Item: TListItem);
    procedure FormShow(Sender: TObject);
    procedure BitBtnStopClick(Sender: TObject);
    procedure BitBtnOpenClick(Sender: TObject);
    procedure lbedtUploadsChange(Sender: TObject);
    procedure BitBtnApplyClick(Sender: TObject);
    procedure BitBtnCancleClick(Sender: TObject);
    procedure BitBtnOKClick(Sender: TObject);
    procedure lbedtUploadsKeyPress(Sender: TObject; var Key: Char);
    procedure lvConnectedChange(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure Button1Click(Sender: TObject);
    procedure btnScheduleClick(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure edtScheduleChange(Sender: TObject);
    procedure txtMsgChange(Sender: TObject);
    procedure btnSendSchClick(Sender: TObject);
    procedure Button6Click(Sender: TObject);
  private
    { Private declarations }
    Atom: TAtom;
    CanClose : Boolean;
    _ServerController: TPKSTController;
    procedure InitServer;
    procedure OnConnect(sender: TObject);
    procedure OnDisConnect(sender: TObject);
    procedure OnNodeInfo(sender: TObject; NodeInfo: TPKSTNodeInfo);
    procedure OnPublishing(sender: TObject);
    procedure OnEndPublish(sender: TObject);
    procedure UploadNotify(sender: TObject);
  public
    { Public declarations }
  end;

var
  PKSTServerForm: TPKSTServerForm;

implementation

uses HashUnit, PKSTutils, Contnrs, frmScheduleEdit, IniFiles;

{$R *.dfm}

procedure TPKSTServerForm.N5Click(Sender: TObject);
begin
  CanClose := true;
  _ServerController.Stop;
  Close;
end;

procedure TPKSTServerForm.FormCreate(Sender: TObject);
begin
  Atom := GlobalAddAtom('PerCast V1.0');
  Canclose := false;
  _ServerController := TPKSTController.Create(True);
  _ServerController.OnConnect := OnConnect;
  _ServerController.OnDisConnect := OnDisConnect;
  _ServerController.OnUploadNotify := UploadNotify;
  InitServer;
  _ServerController.Open;
  ForceDirectories(SlashSep(ExtractFilePath(Application.ExeName),'templet'));
end;

procedure TPKSTServerForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  if canclose then
    exit;
  BitBtnCancle.Click;
  abort;
end;

procedure TPKSTServerForm.ApplicationEvents1Minimize(Sender: TObject);
begin
  ShowWindow(Application.Handle, SW_SHOWMINIMIZED);
  hide;
  ShowWindow(Application.Handle, SW_Hide);

end;

procedure TPKSTServerForm.RxTrayIcon1DblClick(Sender: TObject);
begin
  menuDisplay.Click;
end;

procedure TPKSTServerForm.menuDisplayClick(Sender: TObject);
begin
  if Visible then
  begin
    ShowWindow(Application.Handle, SW_SHOWMINIMIZED);
    hide;
    ShowWindow(Application.Handle, SW_Hide);
  end
  else
  begin
    ShowWindow(Application.Handle, SW_RESTORE);
    show;
    ShowWindow(Application.Handle, SW_SHOW);
  end;
  if Visible then
    menuDisplay.Caption := '隐藏'
  else
    menuDisplay.Caption := '显示'; {}
end;

procedure TPKSTServerForm.InitServer;
var
  GUID: TGUID;
  ini: TIniFile;
begin
  if _ServerController=nil then
    exit;
//  ForceDirectories(ExtractFilePath(Application.ExeName)+'TMP');
  if FileExists(SlashSep(ExtractFilePath(Application.ExeName),'Server.Dat')) then
    _ServerController.Init(SlashSep(ExtractFilePath(Application.ExeName),'Server.Dat'))
  else
  begin
    CreateGUID(GUID);
    _ServerController.Init(GUID);
    _ServerController.Save(SlashSep(ExtractFilePath(Application.ExeName),'Server.Dat'));
  end;
  lbGuid.Caption := GUIDToString(_ServerController.NodeID);
  lbedtName.Text := _ServerController.NodeName;
  lbedtUploads.Text := inttostr(_ServerController.MaxUpLoads);
  chkboxCRC.Checked := _ServerController.CRCCheck;
  bitbtnApply.Enabled := false;
  try
    ini := TIniFile.Create(SlashSep(ExtractFilePath(Application.ExeName),'Server.Dat'));
    edtSchedule.Text := ini.ReadString('Default','Schedule','');
    txtMsg.Lines.Text := ini.ReadString('Default','Message','');
    ini.Free;
    ini := nil;
  except
    if ini<>nil then
      ini.free;
  end;
end;

procedure TPKSTServerForm.FormDestroy(Sender: TObject);
begin
  GlobalDeleteAtom(Atom);
end;

procedure TPKSTServerForm.OnConnect(sender: TObject);
var
  i,j: Integer;
  sGuid: string;
  NodeInfo: TPKSTNodeInfo;
begin
  lvConnected.Items.BeginUpdate;
  if _ServerController.ActiveNodeCount=0 then
  begin
    lvConnected.Items.Clear;
    lvConnected.Items.EndUpdate;
    exit;
  end;

  if lvConnected.Items.Count=0 then
  begin
    for i := 0 to _ServerController.ActiveNodeCount-1 do
    begin
      NodeInfo := _ServerController.ActiveNode[i];
      with lvConnected.Items.Add do
      begin
        Caption := NodeInfo.NodeName+'['+GUIDToString(NodeInfo.NodeID)+']';
        SubItems.Add(GStack.TInAddrToString(NodeInfo.NodeAdd.IP)+':'+inttostr(NodeInfo.NodeAdd.Port)+'['+GStack.TInAddrToString(NodeInfo.NodeAdd.LocalIP)+']');
      end;
    end;
    lvConnected.Items.EndUpdate;
    exit;
  end;

  i := 0;
  j := 0;
  repeat
    sGuid := lvConnected.Items[i].Caption;
    sGuid := copy(sGuid, LastDelimiter('[', sGuid)+1, 38);
    NodeInfo := _ServerController.ActiveNode[j];
    if sGuid = GUIDToString(NodeInfo.NodeID) then
    begin
      lvConnected.Items[i].Caption := NodeInfo.NodeName+'['+GUIDToString(NodeInfo.NodeID)+']';
      lvConnected.Items[i].SubItems[0] := GStack.TInAddrToString(NodeInfo.NodeAdd.IP)+':'+inttostr(NodeInfo.NodeAdd.Port)+'['+GStack.TInAddrToString(NodeInfo.NodeAdd.LocalIP)+']';
      inc(i);
      Inc(j);
    end
    else
    begin
      lvConnected.Items.Delete(i);
    end;
  until (i>=lvConnected.Items.Count-1) or (j>_ServerController.ActiveNodeCount-1);
  for i := i to lvConnected.Items.Count-1 do
   lvConnected.Items.Delete(i);

  for j := j to _ServerController.ActiveNodeCount-1 do
  begin
    NodeInfo := _ServerController.ActiveNode[j];
    with lvConnected.Items.Add do
    begin
      Caption := NodeInfo.NodeName+'['+GUIDToString(NodeInfo.NodeID)+']';
      SubItems.Add(GStack.TInAddrToString(NodeInfo.NodeAdd.IP)+':'+inttostr(NodeInfo.NodeAdd.Port)+'['+GStack.TInAddrToString(NodeInfo.NodeAdd.LocalIP)+']');
    end;
  end;
  lvConnected.Items.EndUpdate;
end;

procedure TPKSTServerForm.OnDisConnect(sender: TObject);
begin
  OnConnect(sender);
end;

procedure TPKSTServerForm.OnNodeInfo(sender: TObject;
  NodeInfo: TPKSTNodeInfo);
var
  s: string;
  i: Integer;
begin
  s := GStack.TInAddrToString(NodeInfo.NodeAdd.IP)+':'+Inttostr(NodeInfo.NodeAdd.Port)+'['+GStack.TInAddrToString(NodeInfo.NodeAdd.LocalIP)+']';
  for i:= 0 to lvConnected.Items.Count-1 do
  begin
    if pos(lvConnected.Items[i].SubItems[0],s)=1 then
    begin
      lvConnected.Items[i].SubItems[0] := s;
      lvConnected.Items[i].Caption := NodeInfo.NodeName+' '+GUIDToString(NodeInfo.NodeID);
      break;
    end;
  end;
end;

procedure TPKSTServerForm.btnSelectClick(Sender: TObject);
var
  s: string;
  i: integer;
begin
  if OpendlgPublish.Execute then
  begin
    if OpendlgPublish.Files.Count<=1 then
      edtPublishFiles.Text := OpendlgPublish.FileName
    else
    begin
      S := '';
      for i:= 0 to OpendlgPublish.Files.Count-1 do
        S := S+'"'+ExtractFileName(OpendlgPublish.Files[i])+'" ';
      edtPublishFiles.Text := s;
    end;
    edtPublishFiles.Enabled := true;
  end;
end;

procedure TPKSTServerForm.btnPublishClick(Sender: TObject);
var
  i: Integer;
  PublishNodes: array of TPKSTNode;
  PublishCount: Integer;
  IP: TIdInAddr;
  Port: Integer;
  SIP: string;
  SPort: string;
  sPos: Integer;
begin
  setlength(PublishNodes, lvConnected.Items.Count);
  PublishCount := 0;
  for i:= lvConnected.Items.Count-1 downto 0 do
  begin
    if not lvConnected.Items[i].Checked then continue;
    SIP := lvConnected.Items[i].SubItems[0];
    sPos := Pos('[',SIP);
    if sPos>0 then
      SIP := Copy(SIP, 1, sPos-1);
    sPos := pos(':',SIP);
    SPort := Copy(SIP, sPos+1, length(SIP)-sPos);
    sIP := Copy(SIP, 1, sPos-1);
    Port := StrToInt(SPort);
    IP := GStack.StringToTInAddr(sIP);
    PublishNodes[PublishCount].IP.S_addr := IP.S_addr;
    PublishNodes[PublishCount].Port := Port;
    Inc(PublishCount);
  end;
  if PublishCount=0 then exit;
  setlength(PublishNodes, PublishCount);
  btnSelect.Enabled := false;
  if pos('SCH://', edtPublishFiles.Text)=1 then
  begin
    OpendlgPublish.Files.Clear;
    OpendlgPublish.Files.Add(edtPublishFiles.Text);
  end;
  if Pos('MSG:',edtPublishFiles.Text)=1 then
  begin
    _ServerController.PublishSubTitle(edtPublishFiles.Text, PublishNodes, OnPublishing, OnEndPublish);
    edtPublishFiles.Text := '';
    edtPublishFiles.Enabled := True;
    exit;
  end;
  edtPublishFiles.Text := '';
  _ServerController.Publish(OpendlgPublish.Files, PublishNodes, OnPublishing, OnEndPublish);
  edtPublishFiles.Enabled := True;
end;

procedure TPKSTServerForm.chkboxSelectClick(Sender: TObject);
var
  i: Integer;
begin
  if chkboxSelect.Checked then
    chkboxSelect.Caption := '清除全部'
  else
    chkboxSelect.Caption := '选择全部';
  for i := lvConnected.Items.Count-1 downto 0 do
    lvConnected.Items[i].Checked := chkboxSelect.Checked;
end;

procedure TPKSTServerForm.edtPublishFilesChange(Sender: TObject);
begin
  btnPublish.Enabled := (edtPublishFiles.Text<>'') and (lvConnected.Items.Count>0);
end;

procedure TPKSTServerForm.OnEndPublish(sender: TObject);
begin
  btnSelect.Enabled := True;
  barPublish.Position := 0;
end;

procedure TPKSTServerForm.OnPublishing(sender: TObject);
var
  DataCount, NodeCount: Integer;
begin
  with TPKSTPublishTask(sender) do
  begin
    DataCount := length(PubDatas);
    NodeCount := length(PubNodes);
    barPublish.Position := ((NodeIndex*DataCount+DataIndex)*100) div (NodeCount*DataCount);
  end;
end;

type
  TController = class(TPKSTController);

procedure TPKSTServerForm.lvUploadsData(Sender: TObject; Item: TListItem);
var
  Filename: string;
  FileSize: Int64;
  DownloadSize: Int64;
begin
  TController(_ServerController)._UpLoadManager.GetUpLoadInfo(Item.Index, Filename,FileSize,DownloadSize);
  Item.Caption := Filename;
  Item.SubItems.add(IntToStr(DownloadSize)+'/'+IntToStr(FileSize)+' 传递中');
end;

procedure TPKSTServerForm.UploadNotify(sender: TObject);
begin
  with TPKSTUpLoadManager(sender) do
  begin
    lvUploads.Items.Count := UpLoadCount;
    lvUploads.Refresh;
  end;
end;

procedure TPKSTServerForm.FormShow(Sender: TObject);
begin
  Top := screen.WorkAreaHeight - Height;
  Left := screen.WorkAreaWidth - Width;
end;

procedure TPKSTServerForm.BitBtnStopClick(Sender: TObject);
begin
  _ServerController.Stop;
  BitBtnStop.Enabled := False;
  BitBtnOpen.Enabled := True;
end;

procedure TPKSTServerForm.BitBtnOpenClick(Sender: TObject);
begin
  _ServerController.Open;
  BitBtnStop.Enabled := True;
  BitBtnOpen.Enabled := False;
end;

procedure TPKSTServerForm.lbedtUploadsChange(Sender: TObject);
begin
  BitBtnApply.Enabled := True;
end;

procedure TPKSTServerForm.BitBtnApplyClick(Sender: TObject);
var
  ini: TIniFile;
begin
  _ServerController.NodeName := lbedtName.Text;
  _ServerController.MaxUpLoads := strtoint(lbedtUploads.Text);
  _ServerController.CRCCheck := chkboxCRC.Checked;
  _ServerController.Save(SlashSep(ExtractFilePath(Application.ExeName),'Server.Dat'));
  BitBtnApply.Enabled := False;
  try
    ini := TIniFile.Create(SlashSep(ExtractFilePath(Application.ExeName),'Server.Dat'));
    ini.WriteString('Default','Schedule',edtSchedule.Text);
    ini.WriteString('Default','Message',txtMsg.Lines.Text);
    ini.Free;
    ini := nil;
  except
    if ini<>nil then
      ini.free;
  end;
end;

procedure TPKSTServerForm.BitBtnCancleClick(Sender: TObject);
begin
  BitBtnApply.Enabled := False;
  InitServer;
  menuDisplay.Click;
end;

procedure TPKSTServerForm.BitBtnOKClick(Sender: TObject);
begin
  BitBtnApply.Click;
  menuDisplay.Click;
end;

procedure TPKSTServerForm.lbedtUploadsKeyPress(Sender: TObject;
  var Key: Char);
begin
  if not (key in ['0'..'9']) then
    Key := #0;
end;

procedure TPKSTServerForm.lvConnectedChange(Sender: TObject;
  Item: TListItem; Change: TItemChange);
begin
  if lvConnected.Items.Count=0 then
    btnPublish.Enabled := false;
end;

type
  TDController = class(TPKSTController);
  TDTaskManager = class(TPKSTTaskManager);
  TDNodeManager = class(TPKSTNodeManager);

procedure TPKSTServerForm.Button1Click(Sender: TObject);
var
  i: integer;
  NodeInfo: TPKSTNodeInfo;
begin
  Memo1.Clear;
  Memo1.Lines.BeginUpdate;
  with TDNodeManager(TDController(_ServerController)._NodeManager) do
  begin
    Memo1.Lines.Add('==============================');
    Memo1.Lines.Add('已经连接上的节点:');
    for i:= 0 to ActiveNodes.Count-1 do
    begin
      NodeInfo := TPKSTNodeInfo(ActiveNodes.Items[i]);
      Memo1.Lines.Add(GUIDToString(NodeInfo.NodeID));
      Memo1.Lines.Add(NodeInfo.NodeName);
      Memo1.Lines.Add(GStack.TInAddrToString(NodeInfo.NodeAdd.IP));
      Memo1.Lines.Add(GStack.TInAddrToString(NodeInfo.NodeAdd.LocalIP));
      Memo1.Lines.Add(Inttostr(NodeInfo.NodeAdd.port));
      memo1.Lines.Add('上次响应时间:'+inttostr(GetTickCount-NodeInfo.Lastresponse)+'MS前');
    end;

    Memo1.Lines.Add('==============================');
    Memo1.Lines.Add('已经断开连接的节点:');
    for i:= 0 to DeActiveNodes.Count-1 do
    begin
      NodeInfo := TPKSTNodeInfo(DeActiveNodes.Items[i]);
      Memo1.Lines.Add(GUIDToString(NodeInfo.NodeID));
      Memo1.Lines.Add(NodeInfo.NodeName);
      Memo1.Lines.Add(GStack.TInAddrToString(NodeInfo.NodeAdd.IP));
      Memo1.Lines.Add(GStack.TInAddrToString(NodeInfo.NodeAdd.LocalIP));
      Memo1.Lines.Add(Inttostr(NodeInfo.NodeAdd.port));
      memo1.Lines.Add('上次响应时间:'+inttostr(GetTickCount-NodeInfo.Lastresponse)+'MS前');
    end;
  end;
  Memo1.Lines.EndUpdate;
end;

procedure TPKSTServerForm.btnScheduleClick(Sender: TObject);
begin
  OpenDlgSchedule.InitialDir := SlashSep(ExtractFilePath(Application.ExeName),'Schedule');
  if OpenDlgSchedule.Execute then
  begin
    edtSchedule.Text := OpenDlgSchedule.FileName;
  end;
end;

procedure TPKSTServerForm.Button3Click(Sender: TObject);
var
  s: string;
begin
  S := NewScheduler;
  if S<>'' then
    edtSchedule.Text := s;
end;

procedure TPKSTServerForm.Button4Click(Sender: TObject);
var
  s: string;
begin
  S := EditScheduler(edtSchedule.Text);
  if S<>'' then
    edtSchedule.Text := s;
end;

procedure TPKSTServerForm.edtScheduleChange(Sender: TObject);
begin
  BitBtnApply.Enabled := True;
  btnSendSch.Enabled := trim(edtSchedule.Text)<>'';
end;

procedure TPKSTServerForm.txtMsgChange(Sender: TObject);
begin
  BitBtnApply.Enabled := True;
end;

procedure TPKSTServerForm.btnSendSchClick(Sender: TObject);
begin
  PageControl1.ActivePageIndex := 0;
  edtPublishFiles.Enabled := False;
  edtPublishFiles.Text := 'SCH://'+edtSchedule.Text;
end;

procedure TPKSTServerForm.Button6Click(Sender: TObject);
begin
  PageControl1.ActivePageIndex := 0;
  edtPublishFiles.Enabled := False;
  edtPublishFiles.Text := 'MSG:'+txtMsg.Lines.Text;
end;

end.
