void function() { "use strict"
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WIP DO NOT USE WIP !!!!!!!!!!!!!!!!!!!!!
DO NOT USE THIS YET.
USE THE 2016 VERSION BELOW PLEASE.
                                                                         
                                                                         
WWWWWWWW                           WWWWWWWWIIIIIIIIIIPPPPPPPPPPPPPPPPP   
W::::::W                           W::::::WI::::::::IP::::::::::::::::P  
W::::::W                           W::::::WI::::::::IP::::::PPPPPP:::::P 
W::::::W                           W::::::WII::::::IIPP:::::P     P:::::P
 W:::::W           WWWWW           W:::::W   I::::I    P::::P     P:::::P
  W:::::W         W:::::W         W:::::W    I::::I    P::::P     P:::::P
   W:::::W       W:::::::W       W:::::W     I::::I    P::::PPPPPP:::::P 
    W:::::W     W:::::::::W     W:::::W      I::::I    P:::::::::::::PP  
     W:::::W   W:::::W:::::W   W:::::W       I::::I    P::::PPPPPPPPP    
      W:::::W W:::::W W:::::W W:::::W        I::::I    P::::P            
       W:::::W:::::W   W:::::W:::::W         I::::I    P::::P            
        W:::::::::W     W:::::::::W          I::::I    P::::P            
         W:::::::W       W:::::::W         II::::::IIPP::::::PP          
          W:::::W         W:::::W          I::::::::IP::::::::P          
           W:::W           W:::W           I::::::::IP::::::::P          
            WWW             WWW            IIIIIIIIIIPPPPPPPPPP          
                                                                       
  
* Manage and Import/Export Chrome Snippets (2018)
* by: http://github.com/soundyogi
* inspired by: https://github.com/bgrins/devtools-snippets/blob/master/import-export/chrome/devtools_import_export.js
*/
// - Templates
// - Test Harness
// - Diy Redux
// - Main
// - Util
// - CSS
// Templates
//
function Layout({getState}){ return `
  
  ${sideMenu({getState})}
  
  Current snippets buffer / state / preview: 
  ${getState().scriptSnippets.forEach((snippet) => { 
  return `
    ${snippet}
  `})}
  
  ${outMenu({getState})}
  
`}
function sideMenu({getState}) { return `
`};
function outMenu({getState}){ return `
  
`}
// Test Harness
//
function log(...x) {
    return console.log(...x)
}
function test(suiteName, f) {
    log(`Test: ${suiteName}`)
    f({ok})
}
function ok(expr, msg) {
    expr ? log('  %c!pass:' + msg, 'color:green') : log('  %c?fail:' + msg, 'color:red')
}
// INIT TEST
test('selftest', function(t) {
    t.ok(true, ' I pass')
    t.ok(false, 'I fail')
})
test("are we inspecting devtools?", ()=>{
    if (location.origin !== "chrome-devtools://devtools")
        console.log("not in devtools of devtools / please inspect devtools again with: (ctrl+shift+i)")
    ok(location.origin === "chrome-devtools://devtools", 'we are in devtools of devtools, good to go')
})
// Naive Redux
//
function createStore(rootReducer, initialState, storeEnhancer) {
  const createStore = storeEnhancer 
    ? storeEnhancer(_createStore) 
    : _createStore
    ;
  return createStore();
  function _createStore() {
    if (!rootReducer) throw Error('rootReducer is missing')
    const _mapSubscribers = {}
    const _rootReducer = rootReducer
    const _store = {
        dispatch: baseDispatch,
        getState,
        subscribe
    }
    let _state = initialState
    return _store;
    function getState() {
        return _state
    }
    function subscribe(f) {
        _mapSubscribers[uuidv4()] = f
    }
    function baseDispatch(action) {
        if (!action || !action.type) throw Error("cant call dispatch without action. stupid.");
        _state = _rootReducer(_state, action)
        for (var subscriberKey in _mapSubscribers) 
          _mapSubscribers[subscriberKey] ? _mapSubscribers[subscriberKey]() : null;
        return true;
    }
  }
}
function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let chain = []
    let dispatch
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)
    return {
      ...store,
      dispatch
    }
  }
}
// Middleware
//
const logger = store => next => action => {
  if(!action.type && action instanceof Function) console.log('thunk: '+action.name)
  else { console.info('event: ', action) }
  let result = next(action)
  return result
}
 
const crashReporter = store => next => action => {
  try {
    return next(action)
  } catch (err) {
    console.error('Caught an exception!', err)
    throw err
  }
}
 
const vanillaPromise = store => next => action => {
  if (typeof action.then !== 'function') {
    return next(action)
  }
  return Promise.resolve(action).then(store.dispatch)
}
 
const thunk = store => next => action =>
  typeof action === 'function'
    ? action(store.dispatch, store.getState)
    : next(action)
/*
function combineReducers(reducerObject:Object):function{}
Combines Reducers by returning a Reducer Reducing Reducers
*/
function combineReducers(reducerObject){
  
 function rootReducer(state, action){
    const newState = {}
    Object.keys(reducerObject).reduce( (newState, currentKey) => { 
      if(!state) state = {}
      // if(!state[currentKey]) state[currentKey] = undefined;
      newState[currentKey] = reducerObject[currentKey](state[currentKey], action) 
      return newState
    }, newState)
    
    return newState
  }
  return rootReducer
}
// Snippets 'Duck'
//
// Actions
//
const SNIPPETS_FETCH_REQUESTED = 'SNIPPETS_FETCH_REQUESTED'
const SNIPPETS_FETCHED = 'SNIPPETS_FETCHED'
const SNIPPET_ADDED    = 'SNIPPET_ADDED'
const SNIPPET_REMOVED  = 'SNIPPET_REMOVED'
// Action Creators / Thunk Creators
//
function snippetsFetchRequested(){
  return function snippetsFetchRequestedThunk(dispatch, getState){
    dispatch({type: SNIPPETS_FETCH_REQUESTED})
    InspectorFrontendHost.getPreferences(prefs=>{
      const lastScriptSnippets = prefs.scriptSnippets
      const snippets = deserialize(lastScriptSnippets)
      const lastIdentifier = prefs.scriptSnippets_lastIdentifier
      dispatch(snippetsFetched({snippets, lastIdentifier}))
    })
  }
}
function snippetsFetched(payload){
  return {type: SNIPPETS_FETCHED, payload}
}
function snippetAdded(){}
function snippetRemoved(){}
const actionCreators = {
  snippetsFetchRequested,
  snippetsFetched,
}
function import_files(event){
  if(!state.gui_switches.append) state.scriptSnippets = []
  const files = event.target.files
  const stack = Object.keys(files)
    .forEach((key)=>{
      const file = files[key]
      const reader = new FileReader()
      reader.fileName = file.name
      reader.onerror = (()=> {throw Error})
      reader.onabort = (()=> {throw Error})
      reader.onload = file_loaded
      reader.readAsText(file)
    })
  function file_loaded(event){
    const content_string = event.target.result
    const fileName = event.target.fileName
    const fileNameNoExt = /(.+?)(\.[^.]*$|$)/.exec(fileName)[1]
    const ext = /\.[0-9a-z]+$/.exec(fileName)[0]
    if(ext === ".json") return import_json(content_string)
    return add_snippet(fileNameNoExt, content_string)
  }
}
function import_json(content_string){
  var json_data = deserialize(content_string)
  json_data.snippets.forEach(snippet => {
    add_snippet(snippet.name, snippet.content)
  })
}
function set_pref(name, data_string){
  InspectorFrontendHost.setPreference(name, data_string)
}
function save_snippets(){
  set_pref( "scriptSnippets", serialize(state.scriptSnippets) )
  set_pref( "scriptSnippets_lastIdentifier", state.lastIdentifier)
  prompt('restart chrome now!')
}
function reset_snippets(){
  var choice = window.confirm("DELETE ALL SNIPPETS IN DEVTOOLS?")
  if(choice) clear_chrome_snippets()
  init()
}
function clear_chrome_snippets(){
  set_pref("scriptSnippets", "[]")
  set_pref("scriptSnippets_lastIdentifier", "0")
}
function add_snippet(name, snippet_content_string){
  if(is_duplicate(name, state.scriptSnippets)) {
    if(!state.gui_switches.rename) return state.scriptSnippets[name] = snippet_content_string
    return add_snippet(name+"copy", snippet_content_string)
  }
  const currentIdentifier = serialize(parseInt(state.lastIdentifier)+1)
  const new_snip = {
    content: snippet_content_string,
    id: currentIdentifier,
    name: name 
  }
  state.scriptSnippets.push( new_snip )
  state.lastIdentifier = currentIdentifier
  update()        
}
function external_bgrins(){
    const brings_snippets = [
    'allcolors',
    'cachebuster',
    'cssreload',
    'cssprettifier',
    'hashlink'
  ]
  brings_snippets.forEach((snippet)=>{
    request('https://raw.githubusercontent.com/bgrins/devtools-snippets/master/snippets/'+snippet+'/'+snippet+'.js', function(request){
      const snippet_content_string = request.target.response
      add_snippet(snippet, snippet_content_string)
    })
  })
}
function external_bahmutov(){
    const bahmutov_snippets = [
    'timing',
    'profile-method-call',
    'time-method-call'
  ]
  bahmutov_snippets.forEach((snippet)=>{
    request('https://raw.githubusercontent.com/bahmutov/code-snippets/master/'+snippet+'.js', function(request){
      const snippet_content_string = request.target.response
      add_snippet(snippet, snippet_content_string)
    })
  })
}
function export_snippets(){
    if(state.gui_switches.format === "json") return download_json()
    return download_js()
}
function download_js(){
    state.scriptSnippets.forEach((snippet)=>{
        download(snippet.name+'.js', snippet.content)
    })
}
function download_json(){
  console.log("json")
    const fileName = serialize(Date())
    const json_data = serialize({'snippets': state.scriptSnippets}, ['snippets', 'name', 'content'], 2)
    download(fileName+".json", json_data)
}
// Reducer
//
const snippetsShape = {
    scriptSnippets: [],
    lastIdentifier: 0,
    //ui
    rename: true,
    format: 'json',
    review: false,
    append: true
}
function snippetsReducer(state = snippetsShape, {TYPE, PL}) {
  if(TYPE === SNIPPETS_FETCHED) return {...state, scriptSnippets: PL.snippets}
  return state
}
// Main logic 
//
const app_window = createWindow("menubar=false, width=1024, height=768", "Chrome Snippets Import/Export/Manager")
const store = createStore(snippetsReducer, undefined, applyMiddleware(logger,thunk,vanillaPromise,crashReporter))
app_window.dispatch = store.dispatch
app_window.getState = store.getState
app_window.events   = actionCreators
app_window.document.head.innerHTML = style();
store.subscribe(function(){
  // console.log(JSON.stringify(store.getState()))
  render(app_window.document.body, Layout)
})
store.dispatch({type: 'first', payload: Date.now()})
// UTIL
//
function render(mountNode, template){
  mountNode.innerHTML = template({getState: store.getState});
}
function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
function uuidv4() {
    // RFC4122 version 4 compliant
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0
          , v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
function request(url, success) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = success;
    xhr.send();
    return xhr;
}
function serialize(object, ...rest) {
    if (!object) throw Error("serialize needs input")
    return JSON.stringify(object, ...rest)
}
function deserialize(string) {
    if (typeof string !== "string") throw Error("deserialize needs a string")
    if (string === "") throw Error("no snippets present")
    return JSON.parse(string)
}
function download(name, data) {
    const Blob = new window.Blob([data],{ 'type': 'text/utf-8' })
    const a = app_window.document.createElement('a')
    a.href = URL.createObjectURL(Blob)
    a.download = name
    a.click()
}
function is_duplicate(name, snippets_arr) {
    const result = snippets_arr.filter(function(snippet) {
        return snippet.name === name
    })
    if (result.length === 0) return false
    return true
}
function createWindow(options, title) {
    const w = window.open("", "", options)
    w.document.title = title
    return w
}
// CSS
//
function style() { return `
`
}
}("live long and prosper");