1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5var harness = {
6  /**
7   * Kick off the test harness.
8   *
9   * Called by harness.html after the dom has been parsed.
10   */
11  init: function() {
12    console.log('Initializing harness...');
13
14    util.installFileErrorToString();
15
16    var self = this;
17
18    function onFilesystem(filesystem) {
19      console.log('Filesystem found.');
20      self.filesystem = filesystem;
21    };
22
23    window.webkitRequestFileSystem(window.PERSISTENT, 16 * 1024 * 1024,
24                                   onFilesystem,
25                                   util.flog('Error initializing filesystem'));
26
27    var paramstr = decodeURIComponent(document.location.search.substr(1));
28    this.params = paramstr ? JSON.parse(paramstr) : {};
29
30    var input = document.getElementById('default-path');
31    input.value = this.params.defaultPath || '';
32    input.addEventListener('keyup', this.onInputKeyUp.bind(this));
33
34    var iframe = document.getElementById('dialog');
35    iframe.setAttribute('src', 'main.html' + document.location.search);
36  },
37
38  onInputKeyUp: function(event) {
39    if (event.keyCode != 13)
40      return;
41
42    this.changePath();
43  },
44
45  changePath: function() {
46    var input = document.getElementById('default-path');
47    this.changeParam('defaultPath', input.value);
48  },
49
50  changeParam: function(name, value) {
51    this.params[name] = value;
52    document.location.href = '?' + JSON.stringify(this.params);
53  },
54
55  /**
56   * 'Reset Fileystem' button click handler.
57   */
58  onClearClick: function() {
59    utils.forEachDirEntry(this.filesystem.root, function(dirEntry) {
60      if (!dirEntry)
61        return console.log('Filesystem reset.');
62
63      console.log('Remove: ' + dirEntry.name);
64
65      if (dirEntry.isDirectory) {
66        dirEntry.removeRecursively();
67      } else {
68        dirEntry.remove();
69      }
70    });
71  },
72
73  /**
74   * Change handler for the 'input type=file' element.
75   */
76  onFilesChange: function(event) {
77    this.importFiles([].slice.call(event.target.files));
78  },
79
80  /**
81   * The fileManager object under test.
82   *
83   * This is a getter rather than a normal property because the fileManager
84   * is initialized asynchronously, and we won't be sure when it'll be
85   * done.  Since harness.fileManager is intended to be used for debugging
86   * from the JS console, we don't really need to be sure it's ready at any
87   * particular time.
88   */
89  get fileManager() {
90    return document.getElementById('dialog').contentWindow.fileManager;
91  },
92
93  /**
94   * Import a list of File objects into harness.filesystem.
95   */
96  importFiles: function(files) {
97    var currentSrc = null;
98    var currentDest = null;
99    var importCount = 0;
100
101    var self = this;
102
103    function onWriterCreated(writer) {
104      writer.onerror = util.flog('Error writing: ' + currentDest.fullPath);
105      writer.onwriteend = function() {
106        console.log('Wrote: ' + currentDest.fullPath);
107        //console.log(writer);
108        //console.log(currentDest);
109        ++importCount;
110        processNextFile();
111      };
112
113      writer.write(currentSrc);
114    }
115
116    function onFileFound(fileEntry) {
117      currentDest = fileEntry;
118      currentDest.createWriter(onWriterCreated,
119                               util.flog('Error creating writer for: ' +
120                                         currentDest.fullPath));
121    }
122
123    function processNextFile() {
124      if (files.length == 0) {
125        console.log('Import complete: ' + importCount + ' file(s)');
126        return;
127      }
128
129      currentSrc = files.shift();
130      var destPath = currentSrc.name.replace(/\^\^/g, '/');
131      self.getOrCreateFile(destPath, onFileFound,
132                              util.flog('Error finding path: ' + destPath));
133    }
134
135    console.log('Start import: ' + files.length + ' file(s)');
136    processNextFile();
137  },
138
139  /**
140   * Locate the file referred to by path, creating directories or the file
141   * itself if necessary.
142   */
143  getOrCreateFile: function(path, successCallback, errorCallback) {
144    var dirname = null;
145    var basename = null;
146
147    function onDirFound(dirEntry) {
148      dirEntry.getFile(basename, { create: true },
149                       successCallback, errorCallback);
150    }
151
152    var i = path.lastIndexOf('/');
153    if (i > -1) {
154      dirname = path.substr(0, i);
155      basename = path.substr(i + 1);
156    } else {
157      basename = path;
158    }
159
160    if (!dirname)
161      return onDirFound(this.filesystem.root);
162
163    this.getOrCreatePath(dirname, onDirFound, errorCallback);
164  },
165
166  /**
167   * Locate the directory referred to by path, creating directories along the
168   * way.
169   */
170  getOrCreatePath: function(path, successCallback, errorCallback) {
171    var names = path.split('/');
172
173    function getOrCreateNextName(dir) {
174      if (!names.length)
175        return successCallback(dir);
176
177      var name;
178      do {
179        name = names.shift();
180      } while (!name || name == '.');
181
182      dir.getDirectory(name, { create: true }, getOrCreateNextName,
183                       errorCallback);
184    }
185
186    getOrCreateNextName(this.filesystem.root);
187  }
188};
189