import fetch from 'unfetch';

const isJsonType = type => type.endsWith('json');

// Fetch an address, expecting a json answer, and throwing if the requests failed.
const jsonThrowingFetch = (...args) =>
  fetch(...args).then((resp) => {
    if (resp.ok) {
      // Every response are supposed to be json.
      return resp.json();
    }
    // If the requests has failed, throw an error.
    return resp.json().then(
      (errorDescr) => {
        const e = new Error(errorDescr.message);
        e.type = errorDescr.type;
        throw e;
      },
      () => {
        throw new Error(resp.statusText);
      }
    );
  });

// Creates an address from an array.
const buildAddress = addrOrPathList =>
  (typeof addrOrPathList === 'string' ? addrOrPathList : addrOrPathList.join('/'));

// Returns an interface toward the provided server address.
export default function getServerInterface(serverAddress) {
  // Ask data to the server.
  const ask = (addrOrPathList, options = {}) => {
    // Build the address (join arrays of path parts).
    const addr = buildAddress(addrOrPathList);
    // Create the request header (all requests are xhr).
    const headers = Object.assign({ 'X-Requested-With': 'XMLHttpRequest' }, options.headers);
    // Create the options for fetch.
    const fetchOptions = Object.assign({ cache: 'no-cache' }, options, { headers });
    // Fetch.
    return jsonThrowingFetch(`${serverAddress}/${addr}`, fetchOptions);
  };

  // Send data to the server.
  const send = (addrOrPathList, content, contentType = 'application/json', options = {}) => {
    // Build the address (join arrays of path parts).
    const addr = buildAddress(addrOrPathList);
    // Set up the request headers, the content type and the request as xhr.
    const headers = Object.assign(
      {
        'Content-Type': contentType,
        'X-Requested-With': 'XMLHttpRequest'
      },
      options.headers
    );
    // Automatically stringify non string content if the content type is json.
    const body =
      typeof content !== 'string' && (isJsonType(contentType) ? JSON.stringify(content) : content);
    // Create the options for fetch.
    const fetchOptions = Object.assign({ method: 'POST', body }, options, { headers });
    // Fetch.
    return jsonThrowingFetch(`${serverAddress}/${addr}`, fetchOptions);
  };

  return {
    experiments: () => ask('experiments'),
    availableRun: xpId => ask(['experiment', xpId, 'available_run']),
    run: (xpId, runId) => ask(['run', xpId, runId]),
    plan: (xpId, runId) => ask(['run', xpId, runId, 'plan']),
    lock: (xpId, runId) => ask(['run', xpId, runId, 'lock']),
    currentTrial: (xpId, runId) => ask(['run', xpId, runId, 'current_trial']),
    postTrialResults: (experimentId, runId, blockNumber, trialNumber, data) =>
      send(['trial', experimentId, runId, blockNumber, trialNumber], data),
    postExperimentDesign: expeDesign => send('import', expeDesign, 'text/xml')
  };
}

@@ -625,51 +625,191 @@
 );%0A%0A
+%0A
 // 
-Creat
+From a server addr
 es
+s
  an
- address from an array
+d the path to an API, return the api address (the main point of this%0A// function is to deal with the different form that can be tacken by api path)
 .%0Aconst 
 buil
@@ -804,21 +804,22 @@
 .%0Aconst 
-build
+getApi
 Address 
@@ -824,275 +824,593 @@
 s = 
-addrOrPathList =%3E%0A  (typeof addrOrPathList === 'string' ? addrOrPathList : addrOrPathList.join('/'));%0A%0A// Returns an interface toward the provided server address.%0Aexport default function getServerInterface(serverAddress) %7B%0A  // Ask data to the server.%0A  const ask
+(serverAddress, apiPath) =%3E %7B%0A  if (typeof apiPath === 'string') %7B%0A    return %5BserverAddress, apiPath%5D.join('/');%0A  %7D else if (apiPath) %7B%0A    return %5BserverAddress, ...apiPath%5D.join('/');%0A  %7D%0A  return serverAddress;%0A%7D;%0A%0A// Returns an interface toward the provided server address.%0Aexport default function getServerInterface(serverAddress, apiPath = 'api') %7B%0A  // Init the api address once and for all.%0A  const apiAddress = getApiAddress(serverAddress, apiPath);%0A%0A  // Get the address of an API endpoint on the server using either a simple string, or an%0A  // array.%0A  const getAddress
  = 
-(
 addr
@@ -1423,85 +1423,171 @@
 List
-, options = %7B%7D) =%3E %7B%0A    // Build the address (join arrays of path parts)
+ =%3E%0A    (typeof addrOrPathList === 'string'%0A      ? %5BapiAddress, addrOrPathList%5D%0A      : %5BapiAddress, ...addrOrPathList%5D).join('/');%0A%0A  // Ask data to the server
 .%0A
-  
   co
@@ -1595,43 +1595,48 @@
 st a
-ddr = buildAddress(addrOrPathList);
+sk = (addrOrPathList, options = %7B%7D) =%3E %7B
 %0A   
@@ -1952,34 +1952,34 @@
 tch(
-%60$%7BserverAddress%7D/$%7Baddr%7D%60
+getAddress(addrOrPathList)
 , fe
@@ -2125,109 +2125,8 @@
 %3E %7B%0A
-    // Build the address (join arrays of path parts).%0A    const addr = buildAddress(addrOrPathList);%0A
     
@@ -2728,34 +2728,34 @@
 tch(
-%60$%7BserverAddress%7D/$%7Baddr%7D%60
+getAddress(addrOrPathList)
 , fe

Update server-interface to comply with xpserver 2.