"use strict";
var fs = require("fs"),
	path = require("path"),
	exec = require("child_process").exec;

var gpioAdmin = "gpio-admin",
	sysFsPath = "/sys/devices/virtual/gpio";

var pinMapping = {
	"3": 0,
	"5": 1,
	"7": 4,
	"8": 14,
	"10": 15,
	"11": 17,
	"12": 18,
	"13": 21,
	"15": 22,
	"16": 23,
	"18": 24,
	"19": 10,
	"21": 9,
	"22": 25,
	"23": 11,
	"24": 8,
	"26": 7
};

function isNumber(number) {
	return !isNaN(parseInt(number, 10));
}

function noop(){}

function handleExecResponse(method, pinNumber, callback) {
	return function(err, stdout, stderr) {
		if(err) {
			console.error("Error when trying to", method, "pin", pinNumber);
			console.error(stderr);
			callback(err);
		} else {
			callback();
		}
	}
}

function sanitizePinNumber(pinNumber) {
	if(!isNumber(pinNumber) || !isNumber(pinMapping[pinNumber])) {
		throw new Error("Pin number isn't valid");
	}

	return parseInt(pinNumber, 10);
}

function sanitizeDirection(direction) {
	direction = (direction || "").toLowerCase().trim();
	if(direction === "in" || direction === "input") {
		return "in";
	} else if(direction === "out" || direction === "output" || !direction) {
		return "out";
	} else {
		throw new Error("Direction must be 'input' or 'output'");
	}
}

var gpio = {
	open: function(pinNumber, direction, callback) {
		pinNumber = sanitizePinNumber(pinNumber);

		if(!callback && typeof direction === "function") {
			callback = direction;
			direction = "out";
		}

		direction = sanitizeDirection(direction);

		exec(gpioAdmin + " export " + pinMapping[pinNumber], handleExecResponse("open", pinNumber, function(err) {
			if(err) return (callback || noop)(err);

			gpio.setDirection(pinNumber, direction, callback);
		}));
	},

	setDirection: function(pinNumber, direction, callback) {
		pinNumber = sanitizePinNumber(pinNumber);
		direction = sanitizeDirection(direction);

		fs.writeFile(sysFsPath + "/gpio" + pinMapping[pinNumber] + "/direction", direction, callback);
	},

	getDirection: function(pinNumber, callback) {
		pinNumber = sanitizePinNumber(pinNumber);

		fs.readFile(sysFsPath + "/gpio" + pinMapping[pinNumber] + "/direction", "utf8", function(err, direction) {
			if(err) return callback(err);
			callback(null, sanitizeDirection(direction.trim()));
		});
	},

	close: function(pinNumber, callback) {
		pinNumber = sanitizePinNumber(pinNumber);

		exec(gpioAdmin + " unexport " + pinMapping[pinNumber], handleExecResponse("close", pinNumber, callback || noop));
	},

	read: function(pinNumber, callback) {
		pinNumber = sanitizePinNumber(pinNumber);

		fs.readFile(sysFsPath + "/gpio" + pinMapping[pinNumber] + "/value", function(err, data) {
			if(err) return (callback || noop)(err);

			(callback || noop)(null, parseInt(data, 10));
		});
	},

	write: function(pinNumber, value, callback) {
		pinNumber = sanitizePinNumber(pinNumber);

		value = !!value?"1":"0";

		fs.writeFile(sysFsPath + "/gpio" + pinMapping[pinNumber] + "/value", value, "utf8", callback);
	}
};

gpio.export = gpio.open;
gpio.unexport = gpio.close;

module.exports = gpio;

@@ -1229,16 +1229,521 @@
 ;%0A%09%7D%0A%7D%0A%0A
+function sanitizePull(pull) %7B%0A%09pull = (pull %7C%7C %22%22).toLowerCase().trim();%0A%09if (pull === %22pullup%22 %7C%7C pull === %22pulldown%22) %7B%0A%09%09return pull;%0A%09%7D else %7B%0A%09%09return %22%22;%0A%09%7D%0A%7D%0A%0Afunction sanitizeOptions(options) %7B%0A%09if (options && typeof options === %22string%22) %7B%0A%09%09var optionTokens = options.split(' ');%0A%09%09options = %7B%7D;%0A%09%09options.direction = optionTokens%5B0%5D;%0A%09%09options.pull = optionTokens%5B1%5D;%0A%09%7D%0A%09options.direction = sanitizeDirection(options.direction);%0A%09options.pull = sanitizePull(options.pull);%0A%09return options;%0A%7D%0A%0A
 var gpio
@@ -1770,33 +1770,31 @@
 (pinNumber, 
-direc
+op
 tion
+s
 , callback) 
@@ -1865,25 +1865,23 @@
  typeof 
-direc
+op
 tion
+s
  === %22fu
@@ -1909,31 +1909,27 @@
 k = 
-direc
+op
 tion
+s
 ;%0A%09%09%09
-direc
+op
 tion
+s
  = %22
@@ -1941,25 +1941,23 @@
 %0A%09%09%7D%0A%0A%09%09
-direc
+op
 tion
+s
  = sanit
@@ -1959,35 +1959,31 @@
 sanitize
-Direction(direc
+Options(op
 tion
+s
 );%0A%0A%09%09ex
@@ -2023,32 +2023,53 @@
 pping%5BpinNumber%5D
+ + %22 %22 + options.pull
 , handleExecResp
@@ -2176,32 +2176,40 @@
 tion(pinNumber, 
+options.
 direction, callb

Allow specifying pullup or pulldown when opening a pin