function compatible( i1, i2 : stuff; greed : boolean ) : boolean;
{ if each sells something the other buys; if greed is true, only org/equip
trades. }
begin
  if i2 = -1 then
    compatible := false
  else if not greed then
    case i1 of
      Class0, 0, 7 : compatible := false;
      1 : compatible := i2 in [2, 4, 6];
      2 : compatible := i2 in [1, 4, 5];
      3 : compatible := i2 in [4, 5, 6];
      4 : compatible := i2 in [1, 2, 3];
      5 : compatible := i2 in [2, 3, 6];
      6 : compatible := i2 in [1, 3, 5];
    end {case}
  else
    case i1 of
      Class0, 0, 1, 6, 7 : compatible := false;
      2, 3 : compatible := i2 in [4,5];
      4, 5 : compatible := i2 in [2,3];
    end; {case}
end;

function deal( good1, good2 : stuff ) : string;
{ Port type "good1" selling to port type "good2" }
const
  ND = 'no deal';
  F  = 'Fuel Ore';
  O  = 'Organics';
  Q  = 'Equipment';
  any = 'anything';

begin
  deal := ND;
  case good1 of
    Class0, 0 : ;  {error}
        1 : if good2 in [0,2,4,6] then deal := F;
        2 : if good2 in [0,1,4,5] then deal := O;
        3 : if good2 in [0,4] then deal := O + ' or ' + F
            else if good2 in [1,5] then deal := O
            else if good2 in [2,6] then deal := F;
        4 : if good2 in [0,1,2,3] then deal := Q;
        5 : if good2 in [0,2] then deal := Q + ' or ' + F
            else if good2 in [1,3] then deal := Q
            else if good2 in [4,6] then deal := F;
        6 : if good2 in [0,1] then deal := Q + ' or ' + O
            else if good2 in [2,3] then deal := Q
            else if good2 in [4,5] then deal := O;
        7 : case good2 of
               Class0,7 : ; {error}
               0 : deal := any;
               1 : deal := Q + ' or ' + O;
               2 : deal := Q + 'or ' + F;
               3 : deal := Q;
               4 : deal := O + ' or ' + F;
               5 : deal := O;
               6 : deal := F;
             end; {case 7}
        end; {case}
end; {deal}

function letterOfGood( g : goods ) : char;
begin
  case g of
    fuel      : LetterOfGood := 'F';
    Organics  : LetterOfGood := 'O';
    Equipment : LetterOfGood := 'E';
  end; {case}
end; {letterOfGood}

procedure ComputeStores( psell, pbuy : PortIndex; var f : real;
                         which : goods; dump : boolean; var into : text);
var
  level1, level2 : integer;
  mss : string;
begin
  level1 := space.ports.data[ psell ].amts[ which ];
  level2 := space.ports.data[ pbuy ].amts[ which ];
  mss := letterOfGood( which ) + ':' + str( level1, 5) + ' to ' + 
         str( level2, 4) + '  ';
  write( mss );
  if dump then
    write( into, mss );
  f := -minreal( -f, -minreal( level1, -level2 ) );
end; {ComputeStores}

procedure DisplayStores( psell, pbuy : PortIndex; s : string;
                        var f : real;
                        EOonly, Dump : boolean;  var T : text );
{ we are given two ports, and a string s that represents the goods we are
going to be trading there.  For each good in s compute the minimum of
the stores we have to sell and amount to purchase, and store the maximum in f,
while also displaying the quantities the port holds. }
begin
  f := 0;
  if not EOonly then
    if pos( 'Fuel', s ) > 0 then
      ComputeStores( psell, pbuy, f, Fuel, Dump, t );
  if pos( 'Organic', s ) > 0 then
    ComputeStores( psell, pbuy, f, Organics, Dump, t );
  if pos( 'Equip', s ) > 0 then
    ComputeStores( psell, pbuy, f, Equipment, Dump, t );
end; {DisplayStores}

procedure PortTradeFactor( s1, s2 : sector;
                           items12, items21 : string;
                           EOonly, FileDump : boolean;
                       var DumpFile : text );
{ Print port information from these two ports corresponding to trading
  items from 1 to 2 and from 2 to 1; compute relative factor. }
var
  p1, p2 : PortIndex;
  factor1, factor2 : real;
  line : string;
begin
  p1 := PortNumber( s1 );
  p2 := PortNumber( s2 );
  if (p1 = 0) or (p2 = 0) then
    begin
      if p1 = 0 then
        line := 'No info available for ' + str( s1 , 1)
      else if p2 = 0 then
        line := 'No info available for ' +  str( s2, 1 );
      writeln( line );
      if Filedump then
        writeln( Dumpfile, line );
    end
  else
    begin
      write( 'Quantities: ' );
      if FileDump then
        write(DumpFile, 'Quantities: ');
      DisplayStores( p1, p2, items12, factor1, EOonly, FileDump, DumpFile);
      DisplayStores( p2, p1, items21, factor2, EOonly, FileDump, DumpFile);
      writeln(' Factor: ', round( sqrt( factor1 * factor2 ) ) );
      if FileDump then
        writeln(DumpFile,' Factor: ', round( sqrt( factor1 * factor2 ) ) );
    end; {else}
end; {PortTradeFactor}

procedure AddEtc( s : sector; var line : string );
{ add special information to code Fighters there or SpaceLane there }
begin
  if space.sectors[s].etc and HasFighters <> nothing then
    line := line + '*'
  else if space.sectors[s].etc and SpaceLane <> nothing then
    line := line + '\';
end; {AddEtc}

procedure DisplayLotsOfPortStuff( s, s1, WhichDistanceIndex : sector;
                                  logging, AsciiDump, showLevels, EquipOnly : boolean;
                                  var f, h : text);
var
  g, g1 : stuff;
  line  : string;
begin
  if logging then
    begin
      writeln( h, 'R', s );
      writeln( h, 'R', s1);
    end; {log}
  g := space.sectors[s].portType;
  g1 := space.sectors[s1].portType;
  line := '(' + str( s, 3);
  AddEtc( s, line );
  line := line + ' & ' + str(s1,3);
  AddEtc( s1, line );
  line := line + ' ) at distance ' + str( distances[WhichDistanceIndex].d,3)
          + ' trading ' +  deal( g, g1) + ' for ' +
           deal( g1, g );
  writeln( line );
  if AsciiDump then
    writeln( f, line );
  if ShowLevels then
    PortTradeFactor( s, s1, deal( g, g1), deal( g1, g ),
                     EquipOnly, AsciiDump, f );
end; {Display Lots of Port Stuff}

procedure SearchPairs( NumPorts : integer;
                       logging : boolean; var h : text;
                       asciiDump : boolean; var f : text;
                       EquipOnly, ShowLevels : boolean );
var
  i         : integer;
  s, s1     : sector;
  g, g1     : stuff;
  t         : warpIndex;
  NumPairs  : integer;
  PauseAt   : integer;
  line      : string;

begin
  NumPairs := 0;
  if ShowLevels then
    PauseAt := 10
  else
    PauseAt := 20;
  for i := 1 to NumPorts do
    begin
      s := distances[ i ].s;
      if space.sectors[s].number <> Unexplored then
        for t := 1 to space.sectors[s].number do
          begin
            s1 := space.sectors[s].data[t];
            if  (space.sectors[ s1].portType <> NotAPort )
                and (s < s1) and IsWarp( s1, s) then
                { must be a port; print only once; check if can get back }
              if compatible( space.sectors[s].portType, space.sectors[s1].portType, EquipOnly ) then
                begin
                  DisplayLotsOfPortStuff(s, s1, i, logging, asciidump, 
                                        showlevels, EquipOnly, f, h);
                  NumPairs := NumPairs + 1;
                  if numPairs mod PauseAt = 0 then
                    if not prompt('more? ') then
                      exit;
                end; {if if}
          end; {for t}
    end; {for i}
end; {SearchPairs}

procedure pairport;
var
  s        : sector;
  QuantInfo,
  Greedy   : boolean;
  NumSectors : integer;
  AsciiDump,
  loggit   : boolean;
  h, fp    : text;
begin
  SortPorts( NumSectors );
  SortDistances( distances, NumSectors );
  QuantInfo := prompt('Do you want to see port quantity information? ');
  greedy := prompt('Do you want to only see Equip/Organic trades? ');
  loggit := LogToDisk( h,
        'Do you want to log the results in a format suitable for upload? ',
        BBSname+'.upl' );
  AsciiDump := LogToDisk( fp,
        'Do you want an echo of the results to an ascii file? ',
        BBSName+'.txt');
  SearchPairs( NumSectors, Loggit, h, AsciiDump, fp, greedy, QuantInfo );
  if loggit then
    close( h );
  if AsciiDump then
    close( fp );
end; {pair ports}