<commit_before>/*
 *  ____    ____    _____    ____    ___     ____ 
 * |  _ \  |  _ \  | ____|  / ___|  / _/    / ___|        Precog (R)
 * | |_) | | |_) | |  _|   | |     | |  /| | |  _         Advanced Analytics Engine for NoSQL Data
 * |  __/  |  _ <  | |___  | |___  |/ _| | | |_| |        Copyright (C) 2010 - 2013 SlamData, Inc.
 * |_|     |_| \_\ |_____|  \____|   /__/   \____|        All Rights Reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the 
 * GNU Affero General Public License as published by the Free Software Foundation, either version 
 * 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 
 * the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this 
 * program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package com.precog.shard
package service

import com.precog.daze._
import com.precog.common._

import com.precog.common.security._
import com.precog.yggdrasil.execution._
import com.precog.yggdrasil.metadata._
import com.precog.yggdrasil.vfs._
import ResourceError._

import blueeyes.core.data._
import blueeyes.core.http._
import blueeyes.core.http.HttpStatusCodes._
import blueeyes.core.service._
import blueeyes.json._
import blueeyes.json.serialization.DefaultSerialization._
import blueeyes.util.Clock

import akka.dispatch.{ Future, ExecutionContext }

import com.weiglewilczek.slf4s.Logging

import scalaz._
import scalaz.Validation._
import scalaz.std.string._
import scalaz.syntax.bifunctor._
import scalaz.syntax.show._
import scalaz.syntax.apply._

class BrowseSupport[M[+_]: Bind](vfs: VFSMetadata[M]) {
  // Essentially doing a leftFlatMap here
  def size(apiKey: APIKey, path: Path): EitherT[M, ResourceError, JNum] = EitherT {
    vfs.size(apiKey, path, Version.Current).run.map {
      case -\/(ResourceError.NotFound(_)) => \/-(0L)
      case otherError @ -\/(_) => otherError
      case okValue @ \/-(_)   => okValue
    }
  } map { JNum(_) }

  def browse(apiKey: APIKey, path: Path): EitherT[M, ResourceError, JArray] = {
    import PathMetadata._
    vfs.findDirectChildren(apiKey, path) map { paths =>
      JArray(
        (paths map { p => 
          JObject(
            "type" -> {
              p.pathType match {
                case DataDir(contentType) => JArray(JString("file"), JString("directory"))
                case DataOnly(contentType) => JArray(JString("file"))
                case PathOnly => JArray(JString("directory"))
              }
            },
            "name" -> JString(p.path.path.substring(1))
          )
        }).toSeq: _*
      )
    }
  }

  def structure(apiKey: APIKey, path: Path, property: CPath): EitherT[M, ResourceError, JValue] = {
    /**
     * This turns a set of types/counts into something usable by strucutre. It
     * will serialize the longs to JNums and unify CNumericTypes under "Number".
     */
    def normalizeTypes(xs: Map[CType, Long]): Map[String, JValue] = {
      xs.foldLeft(Map.empty[String, Long]) {
        case (acc, ((CLong | CDouble | CNum), count)) =>
          acc + ("Number" -> (acc.getOrElse("Number", 0L) + count))
        case (acc, (ctype, count)) =>
          acc + (CType.nameOf(ctype) -> count)
      } mapValues (_.serialize)
    }

    EitherT {
      vfs.pathStructure(apiKey, path, property, Version.Current).fold(
        {
          case ResourceError.NotFound(_) => \/.right(JUndefined)
          case otherError => \/.left(otherError)
        },
        { <commit_msg>Provide contentType field in a path's children's metadata.<commit_after>/*
 *  ____    ____    _____    ____    ___     ____ 
 * |  _ \  |  _ \  | ____|  / ___|  / _/    / ___|        Precog (R)
 * | |_) | | |_) | |  _|   | |     | |  /| | |  _         Advanced Analytics Engine for NoSQL Data
 * |  __/  |  _ <  | |___  | |___  |/ _| | | |_| |        Copyright (C) 2010 - 2013 SlamData, Inc.
 * |_|     |_| \_\ |_____|  \____|   /__/   \____|        All Rights Reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the 
 * GNU Affero General Public License as published by the Free Software Foundation, either version 
 * 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 
 * the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this 
 * program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package com.precog.shard
package service

import com.precog.daze._
import com.precog.common._

import com.precog.common.security._
import com.precog.yggdrasil.execution._
import com.precog.yggdrasil.metadata._
import com.precog.yggdrasil.vfs._
import ResourceError._

import blueeyes.core.data._
import blueeyes.core.http._
import blueeyes.core.http.HttpStatusCodes._
import blueeyes.core.service._
import blueeyes.json._
import blueeyes.json.serialization.DefaultSerialization._
import blueeyes.util.Clock

import akka.dispatch.{ Future, ExecutionContext }

import com.weiglewilczek.slf4s.Logging

import scalaz._
import scalaz.Validation._
import scalaz.std.string._
import scalaz.syntax.bifunctor._
import scalaz.syntax.show._
import scalaz.syntax.apply._

class BrowseSupport[M[+_]: Bind](vfs: VFSMetadata[M]) {
  // Essentially doing a leftFlatMap here
  def size(apiKey: APIKey, path: Path): EitherT[M, ResourceError, JNum] = EitherT {
    vfs.size(apiKey, path, Version.Current).run.map {
      case -\/(ResourceError.NotFound(_)) => \/-(0L)
      case otherError @ -\/(_) => otherError
      case okValue @ \/-(_)   => okValue
    }
  } map { JNum(_) }

  def browse(apiKey: APIKey, path: Path): EitherT[M, ResourceError, JArray] = {
    import PathMetadata._
    vfs.findDirectChildren(apiKey, path) map { paths =>
      JArray(
        (paths map { p =>
          val fields: Map[String, JValue] = p.pathType match {
            case DataDir(contentType) => 
              Map("contentType" -> JString(contentType.value), "type" -> JArray(JString("file"), JString("directory")))
            case DataOnly(contentType) => Map("contentType" -> JString(contentType.value), "type" -> JArray(JString("file")))
            case PathOnly => Map("type" -> JArray(JString("directory")))
          }
          JObject(fields + ("name" -> JString(p.path.path.substring(1))))
        }).toSeq: _*
      )
    }
  }

  def structure(apiKey: APIKey, path: Path, property: CPath): EitherT[M, ResourceError, JValue] = {
    /**
     * This turns a set of types/counts into something usable by strucutre. It
     * will serialize the longs to JNums and unify CNumericTypes under "Number".
     */
    def normalizeTypes(xs: Map[CType, Long]): Map[String, JValue] = {
      xs.foldLeft(Map.empty[String, Long]) {
        case (acc, ((CLong | CDouble | CNum), count)) =>
          acc + ("Number" -> (acc.getOrElse("Number", 0L) + count))
        case (acc, (ctype, count)) =>
          acc + (CType.nameOf(ctype) -> count)
      } mapValues (_.serialize)
    }

    EitherT {
      vfs.pathStructure(apiKey, path, property, Version.Current).fold(
        {
          case ResourceError.NotFound(_) => \/.right(JUndefined)
          case otherError => \/.left(otherError)
        },
        { 
{'fraction_non_alphanumeric': 0.1272066458982347, 'fraction_numerical': 0.0033748701973001036, 'mean_word_length': 2.704326923076923, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7591640', 'n_tokens_mistral': 2508, 'n_tokens_neox': 2424, 'n_words': 635}