lib/agent.js
/**
* @fileOverview A partical object for agents.
* @author kclv@ermitejo.com (MORIYA Masaki, alias Gardejo)
* @license The MIT license (See LICENSE file)
*/
'use strict';
// ================================================================
// Agents
// ================================================================
// ----------------------------------------------------------------
// Namespace for Agents
// ----------------------------------------------------------------
/**
* A namespace for agents.
* @public
*/
kclv.Agent = {};
// ----------------------------------------------------------------
// Base Agent
// ----------------------------------------------------------------
/**
* A base agent.
* An agent (a.k.a. the game client, a dedicated browser (an user agent),
* or a dedicated proxy) has its own format of log files. Their concrete
* operations are delegeted to a tokenizer object.
* Note: If you want to add a tokenizer for an other agent object into the
* library, please send a specification (an actual log file, path of a log
* file, etc.).
* @public
* @param {string} name A name of the agent.
* @param {string} characterSet A character set of agent's log.
* @constructor
*/
kclv.Agent.Base = function(name, characterSet) {
/**
* A name of the agent.
* It's to be used as a part of key in a configuration object tree.
* @protected {string}
* @const
*/
this.name = name;
/**
* A character set of agent's log.
* @protected {string}
* @const
*/
this.CHARACTER_SET = characterSet;
/**
* A delegated file reader object to read a log file.
* @protected {kclv.Stream}
* @const
*/
this.stream = new kclv.Stream();
return;
};
/**
* Build a relation object and get it.
* @public
* @param {string} relationName A name of relation.
* @returns {kclv.Relation.Base} A relation object.
*/
kclv.Agent.Base.prototype.buildRelation = function(relationName) {
var relation = kclv.Factory.getInstance(kclv.Relation, relationName).
insert( this.buildMatrix(relationName) );
// TODO: Strategy
if (relationName === 'Materials') {
relation.select( this.getSelector() );
}
return relation;
};
/**
* Build a matrix (two-dimensional array) representing a log file.
* @protected
* @param {!string} relationName A name of relation.
* (ex. {@code Materials}, {@code Ships})
* @param {string=} opt_concreteRelationName A name of concrete relation.
* (ex. {@code Fuel}, {@code Repair})
* @returns {Array.<Array>} Two-dimensional array representing contents of a
* log file.
* @nosideeffects
*/
kclv.Agent.Base.prototype.buildMatrix = function(
relationName, opt_concreteRelationName
) {
var tokenizer = kclv.Factory.getInstance(
kclv.Tokenizer, [this.name, relationName]
);
return tokenizer.toMatrix(
this.stream.readFile(
this.getPathOf_(opt_concreteRelationName || relationName),
this.CHARACTER_SET
)
);
};
/**
* Build a tuple seleector object and get it.
* @protected
* @returns {kclv.Selector.Base} A tuple selector object.
* @nosideeffects
*/
kclv.Agent.Base.prototype.getSelector = function() {
var configuration = kclv.Configuration.get('relation');
return typeof configuration.duration === 'number' ?
new kclv.Selector.Retrospection(
configuration.duration
) :
new kclv.Selector.Period(
configuration.inception,
configuration.expiration
);
};
/**
* (Abstract) Build an attribute projector object and get it.
* @protected
* @throws {kclv.Exception.AbstractMethod} Always.
*/
kclv.Agent.Base.prototype.getProjector = function() {
throw new kclv.Exception.AbstractMethod();
};
/**
* Get a path string of the specified relation name.
* @private
* @param {!string} relationName A name of relation.
* @returns {string} A path string of the specified log file.
* @nosideeffects
*/
kclv.Agent.Base.prototype.getPathOf_ = function(relationName) {
return kclv.Configuration.get(['agent', this.name, 'path', relationName]);
};
// ----------------------------------------------------------------
// Browser as an Agent ("Manual")
// ----------------------------------------------------------------
/**
* An agent for "Manual".
* It is a simple subtype of {@code kclv.Agent.Base} at the moment.
* @public
* @constructor
* @extends {kclv.Agent.Base}
*/
kclv.Agent.Manual = function() {
kclv.Agent.Base.call(this, 'Manual', 'Shift_JIS');
return;
};
kclv.Agent.Manual.prototype = Object.create(kclv.Agent.Base.prototype);
kclv.Agent.Manual.prototype.constructor = kclv.Agent.Base;
/**
* Build two-dimensional array representing a log file.
* We did not dare to implement the supplement to missing values in the
* {@code kclv.Tokenizer.Manual.Ships.prototype.toMatrix} method,
* because a tokenizer object should devote itself to tokenize strings.
* @protected
* @override
* @param {!string} relationName A name of relation.
* (ex. {@code Materials}, {@code Ships})
* @param {string=} opt_concreteRelationName A name of concrete relation.
* (ex. {@code Fuel}, {@code Repair})
* @returns {Array.<Array>} Two-dimensional array representing contents of a
* log file.
*/
kclv.Agent.Manual.prototype.buildMatrix = function(relationName) {
var matrix =
kclv.Agent.Base.prototype.buildMatrix.call(this, relationName);
if (relationName === 'Ships') {
var EXPERIENCES = kclv.Game.Ships.EXPERIENCES;
matrix = matrix.map( function(columns, index) {
return [
index + 1, // Expedient ID with a line number.
columns[0], // Name.
columns[1], // Abbreviation for ship classification.
columns[2], // Level.
// An experience points with her level (an excess is omitted).
EXPERIENCES[ columns[2] - 1 ]
];
} );
}
return matrix;
};
// ----------------------------------------------------------------
// Agent "KCRDB"
// ----------------------------------------------------------------
/**
* An agent for "KCRDB".
* @public
* @constructor
* @extends {kclv.Agent.Base}
* @see http://hetaregrammer.blog.fc2.com/
*/
kclv.Agent.KCRDB = function() {
kclv.Agent.Base.call(this, 'KCRDB', 'Shift_JIS');
return;
};
kclv.Agent.KCRDB.prototype = Object.create(kclv.Agent.Base.prototype);
kclv.Agent.KCRDB.prototype.constructor = kclv.Agent.Base.prototype;
/**
* Build a relation object and get it.
* @public
* @override
* @param {string} relationName A name of relation.
* @returns {kclv.Relation.Base} A relation object.
*/
kclv.Agent.KCRDB.prototype.buildRelation = function(relationName) {
var relation =
kclv.Agent.Base.prototype.buildRelation.call(this, relationName);
// TODO: Strategy
if (relationName === 'Materials') {
relation.project( this.getProjector() );
}
return relation;
};
/**
* Build an attribute projector object by the configurated kind and get it.
* Note: The default kind is 'Low'.
* @protected
* @override
* @returns {kclv.Projector.Base} An attribute projector object.
* @nosideeffects
*/
kclv.Agent.KCRDB.prototype.getProjector = function() {
var kind = kclv.Configuration.get('relation.values', true) || 'Low';
return kclv.Factory.getInstance(kclv.Projector.Materials, kind);
};
// ----------------------------------------------------------------
// Agent "Logbook"
// ----------------------------------------------------------------
/**
* An agent for "Logbook".
* It is a simple subtype of {@code kclv.Agent.Base} at the moment.
* @public
* @constructor
* @extends {kclv.Agent.Base}
* @see http://kancolle.sanaechan.net/
*/
kclv.Agent.Logbook = function() {
kclv.Agent.Base.call(this, 'Logbook', 'Shift_JIS');
return;
};
kclv.Agent.Logbook.prototype = Object.create(kclv.Agent.Base.prototype);
kclv.Agent.Logbook.prototype.constructor = kclv.Agent.Base;
// ----------------------------------------------------------------
// Agent "LogbookEx"
// ----------------------------------------------------------------
/**
* An agent for "LogbookEx".
* It is a simple subtype of {@code kclv.Agent.Base} at the moment.
* @public
* @constructor
* @extends {kclv.Agent.Logbook}
* @see https://github.com/nekopanda/logbook
*/
kclv.Agent.LogbookEx = function() {
kclv.Agent.Logbook.call(this);
/**
* A name of the agent.
* It's to be used as a part of key in a configuration object tree.
* @protected {string}
* @override
* @const
*/
this.name = 'LogbookEx';
return;
};
kclv.Agent.LogbookEx.prototype = Object.create(kclv.Agent.Logbook.prototype);
kclv.Agent.LogbookEx.prototype.constructor = kclv.Agent.Logbook;
// ----------------------------------------------------------------
// Agent "Sandanshiki Kanpan" (Three Flight Decks)
// ----------------------------------------------------------------
/**
* An agent for "Sandanshiki Kanpan" (Three Flight Decks).
* @public
* @constructor
* @extends {kclv.Agent.Base}
* @see http://3dan.preflight.cc/
*/
kclv.Agent.SandanshikiKanpan = function() {
kclv.Agent.Base.call(this, 'SandanshikiKanpan', 'Shift_JIS');
return;
};
kclv.Agent.SandanshikiKanpan.prototype =
Object.create(kclv.Agent.Base.prototype);
kclv.Agent.SandanshikiKanpan.prototype.constructor = kclv.Agent.Base;
/**
* Build a relation object and get it.
* @public
* @override
* @param {string} relationName A name of relation.
* @returns {kclv.Relation.Base} A relation object.
* @throws {kclv.Exception.InvalidRelation} If the specified relation name is
* not {@code Materials}.
*/
kclv.Agent.SandanshikiKanpan.prototype.buildRelation = function(relationName) {
if (relationName !== 'Materials') {
throw new kclv.Exception.InvalidRelation(relationName, ['Materials']);
}
var contents = {},
MATERIALS = kclv.Game.Materials.MATERIALS,
RADIX = 10;
MATERIALS.forEach( function(material, index) {
if (material === 'Improvement') {
return;
}
// [["date0", value0], ["date1", value0], ...]
this.buildMatrix(relationName, material).forEach( function(columns) {
// { "date0" : [value0, value1, ...], "date1": ... }
var date = columns[0].getTime();
contents[date] = contents[date] || MATERIALS.slice().fill(null);
contents[date][index] = columns[1];
} );
}, this );
return kclv.Factory.getInstance(kclv.Relation, relationName).
insert(
// [ [date0, value0, value1, ...], [date1, value0, ...], ... ]
Object.keys(contents).
map( function(date) {
return [ new Date(parseInt(date, RADIX)) ].
concat(contents[date]);
} ).
sort( function(a, b) { return a[0] - b[0]; } )
).
select( this.getSelector() );
};