File: fgpickbest.cc

package info (click to toggle)
ftpgrab 0.1.1-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 360 kB
  • ctags: 328
  • sloc: cpp: 2,749; makefile: 59
file content (190 lines) | stat: -rw-r--r-- 4,743 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// fgpickbest.cc

#include "fgpickbest.h"

#ifndef _FGALIST_H
#include "fgalist.h"
#endif

#ifndef _FGBDFNAME_H
#include "fgbdfname.h"
#endif

#ifndef _FGDLIST_H
#include "fgdlist.h"
#endif

#ifndef _FGMRANK_H
#include "fgmrank.h"
#endif

#ifndef _FGDLACTION_H
#include "fgdlaction.h"
#endif

#ifndef _FGDELACTION_H
#include "fgdelaction.h"
#endif

#ifndef __SGI_STL_MAP_H
#include <map.h>
#endif

#include <assert.h>

#undef DEBUG_PICKER

struct FGPickBest::Internal_FGPickBest {
  Internal_FGPickBest(const FGString& fname);

  int mRevisionsCount;
  FGBrokenDownFileName mFileBits;
};

FGPickBest::Internal_FGPickBest::Internal_FGPickBest(const FGString& fname)
: mFileBits(fname)
{
}

FGPickBest::FGPickBest(FGConnectionInterface* pConnIf, const FGString& match,
                       int count)
: FGFilePickerInterface(pConnIf)
{
  assert(count > 0);

  mpInternals = new Internal_FGPickBest(match);
  mpInternals->mRevisionsCount = count;
}

FGActionList
FGPickBest::DecideActions(const FGDirListing& localDir,
                          const FGDirListing& remoteDir)
{
  FGActionList ret;

  // Special structures used in this algorithm
  typedef enum _floc {
    kLocal = 0,
    kRemote,
    kBoth
  } EFGFileLocation;

  // n.b. 2nd arg, int, isn't allowed (by ANSI) to be of type
  // EFGFileLocation
  typedef pair<FGFileInfo, int> FGPickMapInfo;
  typedef map<FGMatchRanking, FGPickMapInfo> FGPickMap;
  typedef FGPickMap::iterator FGPickMapIterator;
  typedef FGPickMap::const_iterator FGPickMapCIterator;

  // The sacred map itself
  FGPickMap mainMap;

  // Inject all local matches into map
  vector<FGFileInfo>::const_iterator iFiles;

  for (iFiles = localDir.begin(); iFiles != localDir.end(); iFiles++) {

    // Rule based matching only considers files
    if (!iFiles->IsRegularFile()) {
      continue;
    }
    FGString fileName = iFiles->GetFileName();

    FGMatchRanking thisRank = mpInternals->mFileBits.GetRanking(fileName);

    if (thisRank.IsMatch()) {

#ifdef DEBUG_PICKER
      printf("Local file found\n");
#endif

      FGPickMapInfo newPair;
      newPair.first = *iFiles;
      newPair.second = kLocal;

      FGPickMap::value_type theValue(thisRank, newPair);

      mainMap.insert(theValue);
    }
  }

  // Now inject all remote files into the map
  // Any duplicates get their location flag set to "both"
  for (iFiles = remoteDir.begin(); iFiles != remoteDir.end(); iFiles++) {
    FGString fileName = iFiles->GetFileName();

    // Rule based matching only considers files
    if (!iFiles->IsRegularFile()) {
      continue;
    }

    FGMatchRanking thisRank = mpInternals->mFileBits.GetRanking(fileName);

    // If we have less matches than we want, or the current match is
    // better than our worst match yet, take it
    if (thisRank.IsMatch()) {

#ifdef DEBUG_PICKER
      printf("Remote file found\n");
#endif

      // Two cases - rank value already in map, or not
      FGPickMapIterator iMap = mainMap.find(thisRank);
      if (iMap == mainMap.end()) {
        // Not there yet
        FGPickMapInfo newPair;
        newPair.first = *iFiles;
        newPair.second = kRemote;

        FGPickMap::value_type theValue(thisRank, newPair);

        mainMap.insert(theValue);
      } else {
        // Yes, already there
        iMap->second.second = kBoth;
      }
    }
  }

  // Use our map to decide actions
  // Empty map? Just get out..
  if (mainMap.size() == 0) {
    return ret;
  }

  FGPickMapCIterator iAllMap = mainMap.end();
  // end() points off end => back iterator off one
  iAllMap--;
  int wanted = mpInternals->mRevisionsCount;
  do {

    // Case 1: we are in the wanted region
    if (wanted > 0) {
      // Within the wanted region, make download actions
      // for all "remote only" files
      if (iAllMap->second.second == kRemote) {
        ret.push_back(new FGDownloadAction(iAllMap->second.first.GetFileName(),
                                           mpConnIf,
                                           localDir.GetDirName(),
                                           iAllMap->second.first.GetSize()));
      }
    } else {
      // Case 2: we are in the ditch region
      // Within the ditch region, make delete actions for
      // all "local only" or "local and remote" files
      EFGFileLocation fl = (EFGFileLocation)iAllMap->second.second;
      if (fl == kLocal || fl == kBoth) {
        ret.push_back(new FGDeleteAction(iAllMap->second.first.GetFileName(),
                                         localDir.GetDirName()));
      }
    }

    // Make sure we only try and keep the top N matches on local disk
    wanted--;

    // Decrement the iterator (move towards worse matches)

  } while (iAllMap-- != mainMap.begin());

  return ret;
}